From fc6fac97f2186b22338145f8491563172a61dc87 Mon Sep 17 00:00:00 2001 From: John Joseph Date: Wed, 27 Dec 2023 15:58:55 -0500 Subject: [PATCH] initial commit --- .editorconfig | 4 + .github/workflows/gen-docs.yml | 61 + .github/workflows/ktlint.yml | 25 + .github/workflows/run-tests.yml | 19 + .gitignore | 174 + ...Build & Deploy Robot for Debugging.run.xml | 68 + .run/Build & Deploy Robot.run.xml | 68 + .run/Build Robot.run.xml | 68 + ...Build & Deploy Robot for Debugging.run.xml | 71 + .run/Clean Build & Deploy Robot.run.xml | 71 + .run/Clean Build Robot.run.xml | 163 + .run/Clean.run.xml | 68 + .run/Debug Robot via IP.run.xml | 12 + .run/Debug Robot via USB.run.xml | 12 + .wpilib/wpilib_preferences.json | 6 + 6328 License.md | 21 + README.md | 15 + WPILib-License.md | 24 + build.gradle | 138 + gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 63721 bytes gradle/wrapper/gradle-wrapper.properties | 7 + gradlew | 249 ++ gradlew.bat | 92 + networktables.json | 3 + networktables.json.bck | 3 + settings.gradle | 30 + simgui-ds.json | 97 + simgui.json | 349 ++ src/main/deploy/choreo/BRP-449.chor | 3440 +++++++++++++++++ src/main/kotlin/frc/team449/Main.kt | 9 + src/main/kotlin/frc/team449/RobotBase.kt | 17 + src/main/kotlin/frc/team449/RobotLoop.kt | 139 + .../frc/team449/control/DriveCommand.kt | 24 + .../frc/team449/control/DriveSubsystem.kt | 37 + src/main/kotlin/frc/team449/control/OI.kt | 11 + .../control/TrapezoidalExponentialProfile.kt | 300 ++ .../team449/control/auto/ChoreoFollower.kt | 91 + .../frc/team449/control/auto/ChoreoRoutine.kt | 66 + .../control/auto/ChoreoRoutineStructure.kt | 14 + .../team449/control/auto/ChoreoTrajectory.kt | 116 + .../control/differential/DifferentialDrive.kt | 212 + .../control/differential/DifferentialOIs.kt | 140 + .../control/differential/DifferentialSim.kt | 66 + .../control/holonomic/HolonomicDrive.kt | 11 + .../team449/control/holonomic/HolonomicOI.kt | 141 + .../team449/control/holonomic/MecanumDrive.kt | 204 + .../team449/control/holonomic/SwerveDrive.kt | 482 +++ .../team449/control/holonomic/SwerveModule.kt | 206 + .../holonomic/SwerveOrthogonalCommand.kt | 189 + .../team449/control/holonomic/SwerveSim.kt | 139 + .../team449/control/vision/VisionEstimator.kt | 303 ++ .../team449/control/vision/VisionSubsystem.kt | 106 + .../kotlin/frc/team449/robot2023/Robot.kt | 40 + .../frc/team449/robot2023/auto/AutoUtil.kt | 58 + .../robot2023/auto/routines/DoNothing.kt | 24 + .../robot2023/auto/routines/RoutineChooser.kt | 23 + .../characterization/Characterization.kt | 85 + .../commands/characterization/Regression.kt | 184 + .../commands/driveAlign/OrbitAlign.kt | 55 + .../commands/driveAlign/ProfiledPoseAlign.kt | 119 + .../robot2023/commands/light/BlairChasing.kt | 45 + .../robot2023/commands/light/BreatheHue.kt | 47 + .../team449/robot2023/commands/light/Crazy.kt | 26 + .../robot2023/commands/light/PickupBlink.kt | 33 + .../robot2023/commands/light/Rainbow.kt | 38 + .../robot2023/commands/light/SolidColor.kt | 27 + .../robot2023/constants/MotorConstants.kt | 12 + .../robot2023/constants/RobotConstants.kt | 61 + .../robot2023/constants/auto/AutoConstants.kt | 12 + .../constants/drives/DifferentialConstants.kt | 53 + .../constants/drives/MecanumConstants.kt | 30 + .../constants/drives/SwerveConstants.kt | 61 + .../constants/field/FieldConstants.kt | 43 + .../constants/subsystem/LightConstants.kt | 11 + .../constants/vision/VisionConstants.kt | 93 + .../subsystems/ControllerBindings.kt | 53 + .../robot2023/subsystems/light/Light.kt | 88 + src/main/kotlin/frc/team449/system/AHRS.kt | 83 + .../kotlin/frc/team449/system/SimBattery.kt | 27 + .../kotlin/frc/team449/system/SparkUtil.kt | 79 + .../team449/system/encoder/AbsoluteEncoder.kt | 105 + .../team449/system/encoder/BackupEncoder.kt | 60 + .../frc/team449/system/encoder/Encoder.kt | 116 + .../team449/system/encoder/EncoderCreator.kt | 12 + .../frc/team449/system/encoder/NEOEncoder.kt | 33 + .../frc/team449/system/encoder/QuadEncoder.kt | 37 + .../team449/system/encoder/TalonEncoder.kt | 29 + .../team449/system/motor/SparkMaxCreator.kt | 127 + .../frc/team449/system/motor/TalonCreator.kt | 254 ++ .../frc/team449/system/motor/WrappedMotor.kt | 35 + .../kotlin/frc/team449/util/Properties.kt | 37 + src/main/resources/2023-field.png | Bin 0 -> 950257 bytes vendordeps/NavX.json | 40 + vendordeps/PathplannerLib.json | 38 + vendordeps/PhotonLib-json-1.0.json | 42 + vendordeps/REVLib-2024.json | 74 + vendordeps/WPILibNewCommands.json | 38 + 97 files changed, 10968 insertions(+) create mode 100644 .editorconfig create mode 100644 .github/workflows/gen-docs.yml create mode 100644 .github/workflows/ktlint.yml create mode 100644 .github/workflows/run-tests.yml create mode 100644 .gitignore create mode 100644 .run/Build & Deploy Robot for Debugging.run.xml create mode 100644 .run/Build & Deploy Robot.run.xml create mode 100644 .run/Build Robot.run.xml create mode 100644 .run/Clean Build & Deploy Robot for Debugging.run.xml create mode 100644 .run/Clean Build & Deploy Robot.run.xml create mode 100644 .run/Clean Build Robot.run.xml create mode 100644 .run/Clean.run.xml create mode 100644 .run/Debug Robot via IP.run.xml create mode 100644 .run/Debug Robot via USB.run.xml create mode 100644 .wpilib/wpilib_preferences.json create mode 100644 6328 License.md create mode 100644 README.md create mode 100644 WPILib-License.md create mode 100644 build.gradle create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100644 gradlew create mode 100644 gradlew.bat create mode 100644 networktables.json create mode 100644 networktables.json.bck create mode 100644 settings.gradle create mode 100644 simgui-ds.json create mode 100644 simgui.json create mode 100644 src/main/deploy/choreo/BRP-449.chor create mode 100644 src/main/kotlin/frc/team449/Main.kt create mode 100644 src/main/kotlin/frc/team449/RobotBase.kt create mode 100644 src/main/kotlin/frc/team449/RobotLoop.kt create mode 100644 src/main/kotlin/frc/team449/control/DriveCommand.kt create mode 100644 src/main/kotlin/frc/team449/control/DriveSubsystem.kt create mode 100644 src/main/kotlin/frc/team449/control/OI.kt create mode 100644 src/main/kotlin/frc/team449/control/TrapezoidalExponentialProfile.kt create mode 100644 src/main/kotlin/frc/team449/control/auto/ChoreoFollower.kt create mode 100644 src/main/kotlin/frc/team449/control/auto/ChoreoRoutine.kt create mode 100644 src/main/kotlin/frc/team449/control/auto/ChoreoRoutineStructure.kt create mode 100644 src/main/kotlin/frc/team449/control/auto/ChoreoTrajectory.kt create mode 100644 src/main/kotlin/frc/team449/control/differential/DifferentialDrive.kt create mode 100644 src/main/kotlin/frc/team449/control/differential/DifferentialOIs.kt create mode 100644 src/main/kotlin/frc/team449/control/differential/DifferentialSim.kt create mode 100644 src/main/kotlin/frc/team449/control/holonomic/HolonomicDrive.kt create mode 100644 src/main/kotlin/frc/team449/control/holonomic/HolonomicOI.kt create mode 100644 src/main/kotlin/frc/team449/control/holonomic/MecanumDrive.kt create mode 100644 src/main/kotlin/frc/team449/control/holonomic/SwerveDrive.kt create mode 100644 src/main/kotlin/frc/team449/control/holonomic/SwerveModule.kt create mode 100644 src/main/kotlin/frc/team449/control/holonomic/SwerveOrthogonalCommand.kt create mode 100644 src/main/kotlin/frc/team449/control/holonomic/SwerveSim.kt create mode 100644 src/main/kotlin/frc/team449/control/vision/VisionEstimator.kt create mode 100644 src/main/kotlin/frc/team449/control/vision/VisionSubsystem.kt create mode 100644 src/main/kotlin/frc/team449/robot2023/Robot.kt create mode 100644 src/main/kotlin/frc/team449/robot2023/auto/AutoUtil.kt create mode 100644 src/main/kotlin/frc/team449/robot2023/auto/routines/DoNothing.kt create mode 100644 src/main/kotlin/frc/team449/robot2023/auto/routines/RoutineChooser.kt create mode 100644 src/main/kotlin/frc/team449/robot2023/commands/characterization/Characterization.kt create mode 100644 src/main/kotlin/frc/team449/robot2023/commands/characterization/Regression.kt create mode 100644 src/main/kotlin/frc/team449/robot2023/commands/driveAlign/OrbitAlign.kt create mode 100644 src/main/kotlin/frc/team449/robot2023/commands/driveAlign/ProfiledPoseAlign.kt create mode 100644 src/main/kotlin/frc/team449/robot2023/commands/light/BlairChasing.kt create mode 100644 src/main/kotlin/frc/team449/robot2023/commands/light/BreatheHue.kt create mode 100644 src/main/kotlin/frc/team449/robot2023/commands/light/Crazy.kt create mode 100644 src/main/kotlin/frc/team449/robot2023/commands/light/PickupBlink.kt create mode 100644 src/main/kotlin/frc/team449/robot2023/commands/light/Rainbow.kt create mode 100644 src/main/kotlin/frc/team449/robot2023/commands/light/SolidColor.kt create mode 100644 src/main/kotlin/frc/team449/robot2023/constants/MotorConstants.kt create mode 100644 src/main/kotlin/frc/team449/robot2023/constants/RobotConstants.kt create mode 100644 src/main/kotlin/frc/team449/robot2023/constants/auto/AutoConstants.kt create mode 100644 src/main/kotlin/frc/team449/robot2023/constants/drives/DifferentialConstants.kt create mode 100644 src/main/kotlin/frc/team449/robot2023/constants/drives/MecanumConstants.kt create mode 100644 src/main/kotlin/frc/team449/robot2023/constants/drives/SwerveConstants.kt create mode 100644 src/main/kotlin/frc/team449/robot2023/constants/field/FieldConstants.kt create mode 100644 src/main/kotlin/frc/team449/robot2023/constants/subsystem/LightConstants.kt create mode 100644 src/main/kotlin/frc/team449/robot2023/constants/vision/VisionConstants.kt create mode 100644 src/main/kotlin/frc/team449/robot2023/subsystems/ControllerBindings.kt create mode 100644 src/main/kotlin/frc/team449/robot2023/subsystems/light/Light.kt create mode 100644 src/main/kotlin/frc/team449/system/AHRS.kt create mode 100644 src/main/kotlin/frc/team449/system/SimBattery.kt create mode 100644 src/main/kotlin/frc/team449/system/SparkUtil.kt create mode 100644 src/main/kotlin/frc/team449/system/encoder/AbsoluteEncoder.kt create mode 100644 src/main/kotlin/frc/team449/system/encoder/BackupEncoder.kt create mode 100644 src/main/kotlin/frc/team449/system/encoder/Encoder.kt create mode 100644 src/main/kotlin/frc/team449/system/encoder/EncoderCreator.kt create mode 100644 src/main/kotlin/frc/team449/system/encoder/NEOEncoder.kt create mode 100644 src/main/kotlin/frc/team449/system/encoder/QuadEncoder.kt create mode 100644 src/main/kotlin/frc/team449/system/encoder/TalonEncoder.kt create mode 100644 src/main/kotlin/frc/team449/system/motor/SparkMaxCreator.kt create mode 100644 src/main/kotlin/frc/team449/system/motor/TalonCreator.kt create mode 100644 src/main/kotlin/frc/team449/system/motor/WrappedMotor.kt create mode 100644 src/main/kotlin/frc/team449/util/Properties.kt create mode 100644 src/main/resources/2023-field.png create mode 100644 vendordeps/NavX.json create mode 100644 vendordeps/PathplannerLib.json create mode 100644 vendordeps/PhotonLib-json-1.0.json create mode 100644 vendordeps/REVLib-2024.json create mode 100644 vendordeps/WPILibNewCommands.json diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..7889ba0 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,4 @@ +[{*.kt,*.kts}] +indent_size=2 +max_line_length=200 +ij_kotlin_packages_to_use_import_on_demand = unset \ No newline at end of file diff --git a/.github/workflows/gen-docs.yml b/.github/workflows/gen-docs.yml new file mode 100644 index 0000000..8cdfb9b --- /dev/null +++ b/.github/workflows/gen-docs.yml @@ -0,0 +1,61 @@ +name: Generate docs + +on: + push: + branches: + - main + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages +permissions: + contents: read + pages: write + id-token: write + +# Allow one concurrent deployment +concurrency: + group: "pages" + cancel-in-progress: true + +jobs: + # Single deploy job since we're just deploying + deploy: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Setup Pages + uses: actions/configure-pages@v2 + + - uses: actions/setup-java@v3 + with: + distribution: temurin + java-version: 17 + + - name: Setup Gradle + uses: gradle/gradle-build-action@v2 + with: + gradle-version: current + + - name: Make gradlew executable + run: chmod +x ./gradlew + + - name: Generate HTML with Dokka + run: | + ./gradlew dokkaHtml + + - name: Upload artifact + uses: actions/upload-pages-artifact@v1 + with: + # Upload build HTML + path: './build/dokka/html' + + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v1 + diff --git a/.github/workflows/ktlint.yml b/.github/workflows/ktlint.yml new file mode 100644 index 0000000..178607d --- /dev/null +++ b/.github/workflows/ktlint.yml @@ -0,0 +1,25 @@ +name: Check formatting with ktlint + +on: + push: + pull_request: + +permissions: + contents: read + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Set up JDK 17 + uses: actions/setup-java@v3 + with: + java-version: '17' + distribution: 'temurin' + - name: Give gradlew permission + run: chmod +x ./gradlew + - name: Check formatting using ktlint + run: ./gradlew ktlintCheck diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml new file mode 100644 index 0000000..bfde876 --- /dev/null +++ b/.github/workflows/run-tests.yml @@ -0,0 +1,19 @@ +name: Build and run tests + +on: [push] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Set up JDK 17 + uses: actions/setup-java@v1 + with: + java-version: 17 + - name: Grant execute permission for gradlew + run: chmod +x gradlew + - name: Run tests + run: ./gradlew test diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..74b9648 --- /dev/null +++ b/.gitignore @@ -0,0 +1,174 @@ +# This gitignore has been specially created by the WPILib team. +# If you remove items from this file, intellisense might break. + +### C++ ### +# Prerequisites +*.d + +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app + +### Java ### +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + +### Linux ### +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +### macOS ### +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### VisualStudioCode ### +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json + +### Windows ### +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +### Gradle ### +.gradle +/build/ + +# Ignore Gradle GUI config +gradle-app.setting + +# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) +!gradle-wrapper.jar + +# Cache of project +.gradletasknamecache + +# # Work around https://youtrack.jetbrains.com/issue/IDEA-116898 +# gradle/wrapper/gradle-wrapper.properties + +# # VS Code Specific Java Settings +# DO NOT REMOVE .classpath and .project +.classpath +.project +.settings/ +bin/ + +# IntelliJ +*.iml +*.ipr +*.iws +.idea/ +out/ + +# Fleet +.fleet + +# Simulation GUI and other tools window save file +*-window.json + +*.wpilog \ No newline at end of file diff --git a/.run/Build & Deploy Robot for Debugging.run.xml b/.run/Build & Deploy Robot for Debugging.run.xml new file mode 100644 index 0000000..72b01bf --- /dev/null +++ b/.run/Build & Deploy Robot for Debugging.run.xml @@ -0,0 +1,68 @@ + + + + + + + true + true + false + false + + + + + + + + true + true + false + false + + + + + + + + true + true + false + false + + + \ No newline at end of file diff --git a/.run/Build & Deploy Robot.run.xml b/.run/Build & Deploy Robot.run.xml new file mode 100644 index 0000000..ede63c1 --- /dev/null +++ b/.run/Build & Deploy Robot.run.xml @@ -0,0 +1,68 @@ + + + + + + + true + true + false + false + + + + + + + + true + true + false + false + + + + + + + + true + true + false + false + + + \ No newline at end of file diff --git a/.run/Build Robot.run.xml b/.run/Build Robot.run.xml new file mode 100644 index 0000000..d78b6e7 --- /dev/null +++ b/.run/Build Robot.run.xml @@ -0,0 +1,68 @@ + + + + + + + true + true + false + false + + + + + + + + true + true + false + false + + + + + + + + true + true + false + false + + + \ No newline at end of file diff --git a/.run/Clean Build & Deploy Robot for Debugging.run.xml b/.run/Clean Build & Deploy Robot for Debugging.run.xml new file mode 100644 index 0000000..13d0e1a --- /dev/null +++ b/.run/Clean Build & Deploy Robot for Debugging.run.xml @@ -0,0 +1,71 @@ + + + + + + + true + true + false + false + + + + + + + + true + true + false + false + + + + + + + + true + true + false + false + + + \ No newline at end of file diff --git a/.run/Clean Build & Deploy Robot.run.xml b/.run/Clean Build & Deploy Robot.run.xml new file mode 100644 index 0000000..2091360 --- /dev/null +++ b/.run/Clean Build & Deploy Robot.run.xml @@ -0,0 +1,71 @@ + + + + + + + true + true + false + false + + + + + + + + true + true + false + false + + + + + + + + true + true + false + false + + + \ No newline at end of file diff --git a/.run/Clean Build Robot.run.xml b/.run/Clean Build Robot.run.xml new file mode 100644 index 0000000..65e1aab --- /dev/null +++ b/.run/Clean Build Robot.run.xml @@ -0,0 +1,163 @@ + + + + + + + true + true + false + false + + + + + + + + true + true + false + false + + + + + + + + true + true + false + false + + + + + + + + true + true + false + false + + + + + + + + true + true + false + false + + + + + + + + true + true + false + false + + + + + + + + true + true + false + false + + + \ No newline at end of file diff --git a/.run/Clean.run.xml b/.run/Clean.run.xml new file mode 100644 index 0000000..7ff02fc --- /dev/null +++ b/.run/Clean.run.xml @@ -0,0 +1,68 @@ + + + + + + + true + true + false + false + + + + + + + + true + true + false + false + + + + + + + + true + true + false + false + + + \ No newline at end of file diff --git a/.run/Debug Robot via IP.run.xml b/.run/Debug Robot via IP.run.xml new file mode 100644 index 0000000..e7385cf --- /dev/null +++ b/.run/Debug Robot via IP.run.xml @@ -0,0 +1,12 @@ + + + + + \ No newline at end of file diff --git a/.run/Debug Robot via USB.run.xml b/.run/Debug Robot via USB.run.xml new file mode 100644 index 0000000..90691d3 --- /dev/null +++ b/.run/Debug Robot via USB.run.xml @@ -0,0 +1,12 @@ + + + + + \ No newline at end of file diff --git a/.wpilib/wpilib_preferences.json b/.wpilib/wpilib_preferences.json new file mode 100644 index 0000000..a6475f6 --- /dev/null +++ b/.wpilib/wpilib_preferences.json @@ -0,0 +1,6 @@ +{ + "enableCppIntellisense": false, + "currentLanguage": "java", + "projectYear": "2024beta", + "teamNumber": 449 +} \ No newline at end of file diff --git a/6328 License.md b/6328 License.md new file mode 100644 index 0000000..be97dda --- /dev/null +++ b/6328 License.md @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 FRC 6328 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..5103ed9 --- /dev/null +++ b/README.md @@ -0,0 +1,15 @@ +# Bunnybots 2023 +Our source code for our veteran-led Bunnybot for our 2023 Bunnybots Game: Hibernation Harvest! + +Credit to 6328 for characterization commands and analysis. + +----------------------------- + +## Workflows + +There are currently three workflows, `run-tests.yml` to run tests, `ktlint.yml` to check formatting, and `gen-docs.yml` to generate documentation. Here is how `gen-docs.yml` works: + +- It's triggered whenever you push to `main` +- It runs `./gradlew dokkaHtml` to generate HTML from all our doc comments +- The generated HTML is uploaded and deployed to GitHub Pages +- The documentation is then accessible at https://blair-robot-project.github.io/framework2023/. diff --git a/WPILib-License.md b/WPILib-License.md new file mode 100644 index 0000000..43b62ec --- /dev/null +++ b/WPILib-License.md @@ -0,0 +1,24 @@ +Copyright (c) 2009-2023 FIRST and other WPILib contributors +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of FIRST, WPILib, nor the names of other WPILib + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY FIRST AND OTHER WPILIB CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY NONINFRINGEMENT AND FITNESS FOR A PARTICULAR +PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL FIRST OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..9d9d96f --- /dev/null +++ b/build.gradle @@ -0,0 +1,138 @@ +import edu.wpi.first.gradlerio.GradleRIOPlugin + +plugins { + id "java" + id "idea" + id "org.jetbrains.kotlin.jvm" version "1.8.20" + id "edu.wpi.first.GradleRIO" version "2024.1.1-beta-3" + id "org.jlleitschuh.gradle.ktlint" version "11.3.1" + id "org.jetbrains.dokka" version "1.8.10" +} +java { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 +} + +def ROBOT_MAIN_CLASS = "frc.team449.Main" + +// Define my targets (RoboRIO) and artifacts (deployable files) +// This is added by GradleRIO's backing project DeployUtils. +deploy { + targets { + roborio(getTargetTypeClass('RoboRIO')) { + // Team number is loaded either from the .wpilib/wpilib_preferences.json + // or from command line. If not found an exception will be thrown. + // You can use getTeamOrDefault(team) instead of getTeamNumber if you + // want to store a team number in this file. + team = project.frc.getTeamNumber() + debug = project.frc.getDebugOrDefault(false) + + artifacts { + // First part is artifact name, 2nd is artifact type + // getTargetTypeClass is a shortcut to get the class type using a string + + frcJava(getArtifactTypeClass('FRCJavaArtifact')) { + } + + // Static files artifact + frcStaticFileDeploy(getArtifactTypeClass('FileTreeArtifact')) { + files = project.fileTree('src/main/deploy') + directory = '/home/lvuser/deploy' + } + } + } + } +} + +def deployArtifact = deploy.targets.roborio.artifacts.frcJava + +// Set to true to use debug for JNI. +wpi.java.debugJni = false + +// Set this to true to enable desktop support. +def includeDesktopSupport = false + +// Defining my dependencies. In this case, WPILib (+ friends), and vendor libraries. +// Also defines JUnit 5. +dependencies { + compileOnly 'org.jetbrains:annotations:24.0.1' + + implementation 'com.github.shueja:Monologue:v1.0.0-alpha2' + + implementation("io.javalin:javalin:5.6.2") + implementation("org.slf4j:slf4j-nop:2.0.6") + + implementation 'org.jetbrains.kotlin:kotlin-stdlib' + + implementation "gov.nist.math:jama:1.0.3" + + implementation wpi.java.deps.wpilib() + implementation wpi.java.vendor.java() + + roborioDebug wpi.java.deps.wpilibJniDebug(wpi.platforms.roborio) + roborioDebug wpi.java.vendor.jniDebug(wpi.platforms.roborio) + + roborioRelease wpi.java.deps.wpilibJniRelease(wpi.platforms.roborio) + roborioRelease wpi.java.vendor.jniRelease(wpi.platforms.roborio) + + nativeDebug wpi.java.deps.wpilibJniDebug(wpi.platforms.desktop) + nativeDebug wpi.java.vendor.jniDebug(wpi.platforms.desktop) + simulationDebug wpi.sim.enableDebug() + + nativeRelease wpi.java.deps.wpilibJniRelease(wpi.platforms.desktop) + nativeRelease wpi.java.vendor.jniRelease(wpi.platforms.desktop) + simulationRelease wpi.sim.enableRelease() + + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.2' + testImplementation 'org.junit.jupiter:junit-jupiter-params:5.8.2' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.2' +} + +test { + useJUnitPlatform() + systemProperty 'junit.jupiter.extensions.autodetection.enabled', 'true' +} + +// Simulation configuration (e.g. environment variables). +wpi.sim.addGui().defaultEnabled = true +wpi.sim.addDriverstation() + +// Setting up my Jar File. In this case, adding all libraries into the main jar ('fat jar') +// in order to make them all available at runtime. Also adding the manifest so WPILib +// knows where to look for our Robot Class. +jar { + from { configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } } + from sourceSets.main.allSource + manifest edu.wpi.first.gradlerio.GradleRIOPlugin.javaManifest(ROBOT_MAIN_CLASS) + duplicatesStrategy = DuplicatesStrategy.INCLUDE +} + +repositories { + mavenCentral() + maven { url 'https://jitpack.io' } +} + +sourceSets { + main.kotlin.srcDirs = ['src/main/kotlin'] + main.resources.srcDirs = ['src/main/resources'] +} + +wrapper { + gradleVersion = '7.6' +} + +// pre-commit hook to format +tasks.register('updateGitHooks', Copy) { + from './scripts/pre-commit' + into './.git/hooks' +} + +// Configure jar and deploy tasks +deployArtifact.jarTask = jar +wpi.java.configureExecutableTasks(jar) +wpi.java.configureTestTasks(test) + +// Configure string concat to always inline compile +tasks.withType(JavaCompile) { + options.compilerArgs.add '-XDstringConcat=inline' +} diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..7f93135c49b765f8051ef9d0a6055ff8e46073d8 GIT binary patch literal 63721 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鯊%1Et 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⁢ zv5o9#E7!G0XmdzfsS{efPNi`1b44~SZ4Z8fuX!I}#8g+(wxzQwUT#Xb2(tbY1+EUhGKoT@KEU9Ktl>_0 z%bjDJg;#*gtJZv!-Zs`?^}v5eKmnbjqlvnSzE@_SP|LG_PJ6CYU+6zY6>92%E+ z=j@TZf-iW4(%U{lnYxQA;7Q!b;^brF8n0D>)`q5>|WDDXLrqYU_tKN2>=#@~OE7grMnNh?UOz-O~6 z6%rHy{#h9K0AT+lDC7q4{hw^|q6*Ry;;L%Q@)Ga}$60_q%D)rv(CtS$CQbpq9|y1e zRSrN4;$Jyl{m5bZw`$8TGvb}(LpY{-cQ)fcyJv7l3S52TLXVDsphtv&aPuDk1OzCA z4A^QtC(!11`IsNx_HnSy?>EKpHJWT^wmS~hc^p^zIIh@9f6U@I2 zC=Mve{j2^)mS#U$e{@Q?SO6%LDsXz@SY+=cK_QMmXBIU)j!$ajc-zLx3V60EXJ!qC zi<%2x8Q24YN+&8U@CIlN zrZkcT9yh%LrlGS9`G)KdP(@9Eo-AQz@8GEFWcb7U=a0H^ZVbLmz{+&M7W(nXJ4sN8 zJLR7eeK(K8`2-}j(T7JsO`L!+CvbueT%izanm-^A1Dn{`1Nw`9P?cq;7no+XfC`K(GO9?O^5zNIt4M+M8LM0=7Gz8UA@Z0N+lg+cX)NfazRu z5D)~HA^(u%w^cz+@2@_#S|u>GpB+j4KzQ^&Wcl9f z&hG#bCA(Yk0D&t&aJE^xME^&E-&xGHhXn%}psEIj641H+Nl-}boj;)Zt*t(4wZ5DN z@GXF$bL=&pBq-#vkTkh>7hl%K5|3 z{`Vn9b$iR-SoGENp}bn4;fR3>9sA%X2@1L3aE9yTra;Wb#_`xWwLSLdfu+PAu+o3| zGVnpzPr=ch{uuoHjtw7+_!L_2;knQ!DuDl0R`|%jr+}jFzXtrHIKc323?JO{l&;VF z*L1+}JU7%QJOg|5|Tc|D8fN zJORAg=_vsy{ak|o);@)Yh8Lkcg@$FG3k@ep36BRa^>~UmnRPziS>Z=`Jb2x*Q#`%A zU*i3&Vg?TluO@X0O;r2Jl6LKLUOVhSqg1*qOt^|8*c7 zo(298@+r$k_wQNGHv{|$tW(T8L+4_`FQ{kEW5Jgg{yf7ey4ss_(SNKfz(N9lx&a;< je(UuV8hP?p&}TPdm1I$XmG#(RzlD&B2izSj9sl%y5~4qc literal 0 HcmV?d00001 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..1058752 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=permwrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=permwrapper/dists diff --git a/gradlew b/gradlew new file mode 100644 index 0000000..1aa94a4 --- /dev/null +++ b/gradlew @@ -0,0 +1,249 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..93e3f59 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,92 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/networktables.json b/networktables.json new file mode 100644 index 0000000..41b42e6 --- /dev/null +++ b/networktables.json @@ -0,0 +1,3 @@ +[ + +] diff --git a/networktables.json.bck b/networktables.json.bck new file mode 100644 index 0000000..41b42e6 --- /dev/null +++ b/networktables.json.bck @@ -0,0 +1,3 @@ +[ + +] diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..e23ea1a --- /dev/null +++ b/settings.gradle @@ -0,0 +1,30 @@ +import org.gradle.internal.os.OperatingSystem + +pluginManagement { + repositories { + mavenLocal() + gradlePluginPortal() + String frcYear = '2024' + File frcHome + if (OperatingSystem.current().isWindows()) { + String publicFolder = System.getenv('PUBLIC') + if (publicFolder == null) { + publicFolder = "C:\\Users\\Public" + } + def homeRoot = new File(publicFolder, "wpilib") + frcHome = new File(homeRoot, frcYear) + } else { + def userFolder = System.getProperty("user.home") + def homeRoot = new File(userFolder, "wpilib") + frcHome = new File(homeRoot, frcYear) + } + def frcHomeMaven = new File(frcHome, 'maven') + maven { + name 'frcHome' + url frcHomeMaven + } + } +} + +Properties props = System.getProperties() +props.setProperty("org.gradle.internal.native.headers.unresolved.dependencies.ignore", "true") diff --git a/simgui-ds.json b/simgui-ds.json new file mode 100644 index 0000000..69b1a3c --- /dev/null +++ b/simgui-ds.json @@ -0,0 +1,97 @@ +{ + "keyboardJoysticks": [ + { + "axisConfig": [ + { + "decKey": 65, + "incKey": 68 + }, + { + "decKey": 87, + "incKey": 83 + }, + { + "decKey": 69, + "decayRate": 0.0, + "incKey": 82, + "keyRate": 0.009999999776482582 + } + ], + "axisCount": 3, + "buttonCount": 4, + "buttonKeys": [ + 90, + 88, + 67, + 86 + ], + "povConfig": [ + { + "key0": 328, + "key135": 323, + "key180": 322, + "key225": 321, + "key270": 324, + "key315": 327, + "key45": 329, + "key90": 326 + } + ], + "povCount": 1 + }, + { + "axisConfig": [ + { + "decKey": 74, + "incKey": 76 + }, + { + "decKey": 73, + "incKey": 75 + } + ], + "axisCount": 2, + "buttonCount": 4, + "buttonKeys": [ + 77, + 44, + 46, + 47 + ], + "povCount": 0 + }, + { + "axisConfig": [ + { + "decKey": 263, + "incKey": 262 + }, + { + "decKey": 265, + "incKey": 264 + } + ], + "axisCount": 2, + "buttonCount": 6, + "buttonKeys": [ + 260, + 268, + 266, + 261, + 269, + 267 + ], + "povCount": 0 + }, + { + "axisCount": 0, + "buttonCount": 0, + "povCount": 0 + } + ], + "robotJoysticks": [ + { + "guid": "Keyboard0" + } + ] +} diff --git a/simgui.json b/simgui.json new file mode 100644 index 0000000..4739e7f --- /dev/null +++ b/simgui.json @@ -0,0 +1,349 @@ +{ + "HALProvider": { + "Addressable LEDs": { + "0": { + "columns": 2, + "order": 1 + }, + "window": { + "visible": true + } + } + }, + "NTProvider": { + "types": { + "/FMSInfo": "FMSInfo", + "/LiveWindow/Ungrouped/DigitalInput[5]": "Digital Input", + "/LiveWindow/Ungrouped/DigitalInput[6]": "Digital Input", + "/LiveWindow/Ungrouped/DigitalInput[7]": "Digital Input", + "/LiveWindow/Ungrouped/DigitalInput[8]": "Digital Input", + "/LiveWindow/Ungrouped/DigitalInput[9]": "Digital Input", + "/LiveWindow/Ungrouped/PIDController[10]": "PIDController", + "/LiveWindow/Ungrouped/PIDController[11]": "PIDController", + "/LiveWindow/Ungrouped/PIDController[12]": "PIDController", + "/LiveWindow/Ungrouped/PIDController[13]": "PIDController", + "/LiveWindow/Ungrouped/PIDController[14]": "PIDController", + "/LiveWindow/Ungrouped/PIDController[15]": "PIDController", + "/LiveWindow/Ungrouped/PIDController[16]": "PIDController", + "/LiveWindow/Ungrouped/PIDController[17]": "PIDController", + "/LiveWindow/Ungrouped/PIDController[18]": "PIDController", + "/LiveWindow/Ungrouped/PIDController[19]": "PIDController", + "/LiveWindow/Ungrouped/PIDController[1]": "PIDController", + "/LiveWindow/Ungrouped/PIDController[20]": "PIDController", + "/LiveWindow/Ungrouped/PIDController[21]": "PIDController", + "/LiveWindow/Ungrouped/PIDController[22]": "PIDController", + "/LiveWindow/Ungrouped/PIDController[23]": "PIDController", + "/LiveWindow/Ungrouped/PIDController[24]": "PIDController", + "/LiveWindow/Ungrouped/PIDController[25]": "PIDController", + "/LiveWindow/Ungrouped/PIDController[26]": "PIDController", + "/LiveWindow/Ungrouped/PIDController[27]": "PIDController", + "/LiveWindow/Ungrouped/PIDController[28]": "PIDController", + "/LiveWindow/Ungrouped/PIDController[29]": "PIDController", + "/LiveWindow/Ungrouped/PIDController[2]": "PIDController", + "/LiveWindow/Ungrouped/PIDController[30]": "PIDController", + "/LiveWindow/Ungrouped/PIDController[31]": "PIDController", + "/LiveWindow/Ungrouped/PIDController[32]": "PIDController", + "/LiveWindow/Ungrouped/PIDController[33]": "PIDController", + "/LiveWindow/Ungrouped/PIDController[34]": "PIDController", + "/LiveWindow/Ungrouped/PIDController[35]": "PIDController", + "/LiveWindow/Ungrouped/PIDController[36]": "PIDController", + "/LiveWindow/Ungrouped/PIDController[3]": "PIDController", + "/LiveWindow/Ungrouped/PIDController[4]": "PIDController", + "/LiveWindow/Ungrouped/PIDController[5]": "PIDController", + "/LiveWindow/Ungrouped/PIDController[6]": "PIDController", + "/LiveWindow/Ungrouped/PIDController[7]": "PIDController", + "/LiveWindow/Ungrouped/PIDController[8]": "PIDController", + "/LiveWindow/Ungrouped/PIDController[9]": "PIDController", + "/LiveWindow/Ungrouped/navX-Sensor[1]": "Gyro", + "/LiveWindow/Ungrouped/navX-Sensor[4]": "Gyro", + "/Monologuing/field": "Field2d", + "/Monologuing/robot/elevator/mech": "Mechanism2d", + "/Monologuing/routineChooser": "String Chooser", + "/Monologuing/scheduler": "Scheduler", + "/SmartDashboard/Command Scheduler": "Scheduler", + "/SmartDashboard/Elevator Visual": "Mechanism2d", + "/SmartDashboard/Field": "Field2d", + "/SmartDashboard/Routine Chooser": "String Chooser", + "/SmartDashboard/VisionSystemSim-main/Sim Field": "Field2d" + }, + "windows": { + "/Monologuing/field": { + "bumpers": { + "length": 0.9271000027656555, + "width": 0.8510000109672546 + }, + "height": 8.229599952697754, + "image": "C:\\Users\\jpoth\\Downloads\\field(1).png", + "odo": { + "color": [ + 0.7647056579589844, + 0.0, + 1.0, + 255.0 + ] + }, + "units": "meters", + "width": 16.459199905395508, + "window": { + "visible": true + } + }, + "/SmartDashboard/Command Scheduler": { + "window": { + "visible": true + } + }, + "/SmartDashboard/Field": { + "height": 8.013679504394531, + "width": 16.541748046875 + }, + "/SmartDashboard/Routine Chooser": { + "window": { + "visible": true + } + }, + "/SmartDashboard/VisionSystemSim-main/Sim Field": { + "EstimatedRobot": { + "color": [ + 0.7058820724487305, + 0.0, + 1.0, + 255.0 + ] + }, + "Robot": { + "color": [ + 0.0, + 1.0, + 0.08823513984680176, + 255.0 + ] + }, + "VisionEstimation": { + "color": [ + 0.17647027969360352, + 0.0, + 1.0, + 255.0 + ] + }, + "bottom": 544, + "builtin": "2023 Charged Up", + "cameras": { + "arrows": false, + "style": "Track" + }, + "height": 8.013679504394531, + "left": 46, + "right": 1088, + "top": 36, + "width": 16.541748046875, + "window": { + "visible": true + } + } + } + }, + "NetworkTables": { + "Retained Values": { + "open": false + }, + "transitory": { + "CameraPublisher": { + "arducam-processed": { + "open": true, + "string[]##v_/CameraPublisher/arducam-processed/streams": { + "open": true + } + }, + "open": true + }, + "Monologuing": { + "open": true, + "robot": { + "drive": { + "boolean[]##v_/Monologuing/robot/drive/2.1 Used Last Vision Estimate?": { + "open": true + }, + "double[]##v_/Monologuing/robot/drive/1.1 Estimated Pose": { + "open": true + }, + "double[]##v_/Monologuing/robot/drive/1.2 Vision Pose": { + "open": true + }, + "double[]##v_/Monologuing/robot/drive/1.3 Current Chassis Speeds": { + "open": true + }, + "double[]##v_/Monologuing/robot/drive/1.4 Desired Chassis Speeds": { + "open": true + }, + "double[]##v_/Monologuing/robot/drive/1.7 Vision Stats": { + "open": true + }, + "double[]##v_/Monologuing/robot/drive/2.1 Current Rotation": { + "open": true + }, + "double[]##v_/Monologuing/robot/drive/2.2 Desired Rotation": { + "open": true + }, + "double[]##v_/Monologuing/robot/drive/2.2 Number of Targets": { + "open": true + }, + "double[]##v_/Monologuing/robot/drive/2.3 Avg Tag Distance": { + "open": true + }, + "double[]##v_/Monologuing/robot/drive/2.4 Average Ambiguity": { + "open": true + }, + "double[]##v_/Monologuing/robot/drive/2.5 Cam Height Error": { + "open": true + }, + "double[]##v_/Monologuing/robot/drive/Current Chassis Speeds": { + "open": true + }, + "double[]##v_/Monologuing/robot/drive/Estimated Pose": { + "open": true + }, + "open": true + }, + "intake": { + "double[]##v_/Monologuing/robot/intake/3.1 Intake 3D Position": { + "open": true + } + }, + "open": true + } + }, + "Shuffleboard": { + "SwerveSim": { + "BLModule": { + "BLDrive": { + "open": true + }, + "BLTurn": { + "BLTurnEnc": { + "open": true + }, + "open": true + }, + "open": true + }, + "open": true + }, + "open": true + }, + "SmartDashboard": { + "VisionSystemSim-main": { + "open": true + }, + "open": true + }, + "photonvision": { + "arducam": { + "open": true + }, + "open": true + } + } + }, + "NetworkTables Info": { + "Connections": { + "open": true + }, + "Server": { + "open": true + } + }, + "Plot": { + "Plot <0>": { + "plots": [ + { + "backgroundColor": [ + 0.0, + 0.0, + 0.0, + 0.8500000238418579 + ], + "height": 852, + "series": [ + { + "color": [ + 0.3333333432674408, + 0.658823549747467, + 0.4078431725502014, + 1.0 + ], + "id": "NT:/Monologuing/robot/elevator/2.3 Desired Pos" + }, + { + "color": [ + 0.7686275243759155, + 0.30588236451148987, + 0.32156863808631897, + 1.0 + ], + "id": "NT:/Monologuing/robot/elevator/2.4 Desired Vel" + }, + { + "color": [ + 0.3333333432674408, + 0.658823549747467, + 0.4078431725502014, + 1.0 + ], + "id": "NT:/Monologuing/robot/elevator/2.1 Estimated Pos" + }, + { + "color": [ + 0.7686275243759155, + 0.30588236451148987, + 0.32156863808631897, + 1.0 + ], + "id": "NT:/Monologuing/robot/elevator/2.2 Estimated Vel" + } + ] + } + ], + "window": { + "visible": false + } + }, + "Plot <1>": { + "plots": [ + { + "backgroundColor": [ + 0.0, + 0.0, + 0.0, + 0.8500000238418579 + ], + "height": 859, + "series": [ + { + "color": [ + 0.2980392277240753, + 0.44705885648727417, + 0.6901960968971252, + 1.0 + ], + "id": "NT:/Monologuing/robot/elevator/1.1 Last voltage" + }, + { + "color": [ + 0.8666667342185974, + 0.5176470875740051, + 0.32156863808631897, + 1.0 + ], + "id": "NT:/Monologuing/robot/drive/4.1 Driving[0]" + } + ] + } + ], + "window": { + "visible": false + } + } + } +} diff --git a/src/main/deploy/choreo/BRP-449.chor b/src/main/deploy/choreo/BRP-449.chor new file mode 100644 index 0000000..b7f7f16 --- /dev/null +++ b/src/main/deploy/choreo/BRP-449.chor @@ -0,0 +1,3440 @@ +{ + "version": "v0.0.1", + "robotConfiguration": { + "mass": 60.0, + "rotationalInertia": 6, + "wheelMaxTorque": 1.675, + "wheelMaxVelocity": 88.06, + "wheelbase": 0.6223, + "trackWidth": 0.5461, + "bumperLength": 0.9271, + "bumperWidth": 0.851, + "wheelRadius": 0.0508 + }, + "paths": { + "4": { + "waypoints": [ + { + "x": 9.335601806640625, + "y": 0.9251009821891785, + "heading": 0, + "velocityMagnitude": 0, + "velocityAngle": 1.5638036450126473, + "translationConstrained": true, + "headingConstrained": true, + "velocityMagnitudeConstrained": true, + "velocityAngleConstrained": true, + "angularVelocity": 0, + "angularVelocityConstrained": true, + "controlIntervalCount": 0 + }, + { + "x": 9.422258377075195, + "y": 4.109755992889404, + "heading": 0, + "velocityMagnitude": 0, + "velocityAngle": 1.5605920080832691, + "translationConstrained": true, + "headingConstrained": true, + "velocityMagnitudeConstrained": false, + "velocityAngleConstrained": true, + "angularVelocity": 0, + "angularVelocityConstrained": false, + "controlIntervalCount": 0 + }, + { + "x": 9.433091163635254, + "y": 5.9728875160217285, + "heading": 0, + "velocityMagnitude": 0, + "velocityAngle": -2.57429121999024, + "translationConstrained": true, + "headingConstrained": true, + "velocityMagnitudeConstrained": false, + "velocityAngleConstrained": true, + "angularVelocity": 0, + "angularVelocityConstrained": false, + "controlIntervalCount": 0 + }, + { + "x": 6.638393402099609, + "y": 4.185581207275391, + "heading": 0, + "velocityMagnitude": 0, + "velocityAngle": 0.021273206755077097, + "translationConstrained": true, + "headingConstrained": true, + "velocityMagnitudeConstrained": false, + "velocityAngleConstrained": true, + "angularVelocity": 0, + "angularVelocityConstrained": false, + "controlIntervalCount": 0 + }, + { + "x": 10.98208999633789, + "y": 4.218077659606934, + "heading": 0, + "velocityMagnitude": 0, + "velocityAngle": 0, + "translationConstrained": true, + "headingConstrained": true, + "velocityMagnitudeConstrained": true, + "velocityAngleConstrained": false, + "angularVelocity": 0, + "angularVelocityConstrained": true, + "controlIntervalCount": 0 + } + ], + "trajectory": [ + { + "timestamp": 0, + "x": 9.335601806640623, + "y": 0.9251009821891784, + "heading": 7.433229425921144e-37, + "velocityX": 6.410368319804879e-34, + "velocityY": 1.619305695497464e-35, + "angularVelocity": 0 + }, + { + "timestamp": 0.038511682074740636, + "x": 9.335727411279946, + "y": 0.9291167961323064, + "heading": -1.0037001746092558e-19, + "velocityX": 0.0032614685351080117, + "velocityY": 0.10427521538359463, + "angularVelocity": -2.606222766890331e-18 + }, + { + "timestamp": 0.07702336414948127, + "x": 9.335978620458318, + "y": 0.9371484239902014, + "heading": -3.196922765189427e-19, + "velocityX": 0.006522934466587738, + "velocityY": 0.20855043003075938, + "angularVelocity": -5.694954314081186e-18 + }, + { + "timestamp": 0.11553504622422191, + "x": 9.336355434069395, + "y": 0.9491958657327835, + "heading": -5.546914236937845e-19, + "velocityX": 0.00978439763664558, + "velocityY": 0.31282564389686435, + "angularVelocity": -6.102022705973671e-18 + }, + { + "timestamp": 0.15404672829896254, + "x": 9.336857852000183, + "y": 0.9652591213280927, + "heading": -8.231194396614724e-19, + "velocityX": 0.013045857872694985, + "velocityY": 0.41710085693309584, + "angularVelocity": -6.970041653063732e-18 + }, + { + "timestamp": 0.1925584103737032, + "x": 9.337485874130397, + "y": 0.9853381907421074, + "heading": -1.1249774836078608e-18, + "velocityX": 0.01630731498544771, + "velocityY": 0.5213760690859163, + "angularVelocity": -7.838090699792929e-18 + }, + { + "timestamp": 0.23107009244844384, + "x": 9.338239500331737, + "y": 1.009433073938538, + "heading": -1.4602674866494168e-18, + "velocityX": 0.019568768766686964, + "velocityY": 0.625651280296435, + "angularVelocity": -8.706189890224704e-18 + }, + { + "timestamp": 0.2695817745231845, + "x": 9.33911873046705, + "y": 1.0375437708785924, + "heading": -1.828272374911586e-18, + "velocityX": 0.02283021898665661, + "velocityY": 0.7299264904996693, + "angularVelocity": -9.555669426461947e-18 + }, + { + "timestamp": 0.30809345659792514, + "x": 9.34012356438939, + "y": 1.0696702815207073, + "heading": -2.2506326768457678e-18, + "velocityX": 0.026091665390984165, + "velocityY": 0.8342016996236742, + "angularVelocity": -1.0967070115315713e-17 + }, + { + "timestamp": 0.3466051386726658, + "x": 9.341254001940927, + "y": 1.1058126058202418, + "heading": -2.7064302356007662e-18, + "velocityX": 0.029353107697033986, + "velocityY": 0.9384769075885119, + "angularVelocity": -1.1835306849731083e-17 + }, + { + "timestamp": 0.38511682074740644, + "x": 9.342510042951687, + "y": 1.1459707437291202, + "heading": -3.1731399809933165e-18, + "velocityX": 0.03261454558955918, + "velocityY": 1.0427521143050211, + "angularVelocity": -1.2118654298759269e-17 + }, + { + "timestamp": 0.4236285028221471, + "x": 9.343891687238102, + "y": 1.1901446951954218, + "heading": -3.649862808122623e-18, + "velocityX": 0.03587597871548388, + "velocityY": 1.1470273196733423, + "angularVelocity": -1.2378655457067792e-17 + }, + { + "timestamp": 0.46214018489688774, + "x": 9.345398934601302, + "y": 1.238334460162899, + "heading": -4.135624468405925e-18, + "velocityX": 0.03913740667759855, + "velocityY": 1.2513025235811337, + "angularVelocity": -1.2613359152524966e-17 + }, + { + "timestamp": 0.5006518669716283, + "x": 9.347031784825132, + "y": 1.2905400385704136, + "heading": -4.654835473451493e-18, + "velocityX": 0.04239882902688467, + "velocityY": 1.3555777259014021, + "angularVelocity": -1.3481909782101063e-17 + }, + { + "timestamp": 0.539163549046369, + "x": 9.348790237673777, + "y": 1.3467614303512696, + "heading": -5.207498428769433e-18, + "velocityX": 0.045660245253095165, + "velocityY": 1.4598529264898374, + "angularVelocity": -1.4350528088444295e-17 + }, + { + "timestamp": 0.5776752311211096, + "x": 9.350674292888971, + "y": 1.40699863543242, + "heading": -5.821509101817224e-18, + "velocityX": 0.04892165477309202, + "velocityY": 1.564128125181516, + "angularVelocity": -1.594349199585464e-17 + }, + { + "timestamp": 0.6161869131958503, + "x": 9.352683950186623, + "y": 1.4712516537335134, + "heading": -6.468978620099235e-18, + "velocityX": 0.05218305691626845, + "velocityY": 1.6684033217867782, + "angularVelocity": -1.681228931633707e-17 + }, + { + "timestamp": 0.6546985952705909, + "x": 9.354819209252733, + "y": 1.539520485165741, + "heading": -7.14991115378602e-18, + "velocityX": 0.055444450906134805, + "velocityY": 1.7726785160860195, + "angularVelocity": -1.76811949201849e-17 + }, + { + "timestamp": 0.6932102773453316, + "x": 9.357080069738416, + "y": 1.6118051296304272, + "heading": -6.612093128484066e-18, + "velocityX": 0.05870583583678967, + "velocityY": 1.8769537078230385, + "angularVelocity": 1.396506225469321e-17 + }, + { + "timestamp": 0.7317219594200722, + "x": 9.359466531253739, + "y": 1.688105587017289, + "heading": -6.110201743902472e-18, + "velocityX": 0.06196721064247079, + "velocityY": 1.9812288966964262, + "angularVelocity": 1.3032185803885427e-17 + }, + { + "timestamp": 0.7702336414948129, + "x": 9.361978593360037, + "y": 1.7684218572022588, + "heading": -5.660092663100996e-18, + "velocityX": 0.06522857405759094, + "velocityY": 2.085504082348265, + "angularVelocity": 1.1687598848392519e-17 + }, + { + "timestamp": 0.8087453235695535, + "x": 9.36461625556015, + "y": 1.852753940044729, + "heading": -5.2434652778834646e-18, + "velocityX": 0.06848992456345294, + "velocityY": 2.1897792643490614, + "angularVelocity": 1.0818208191711212e-17 + }, + { + "timestamp": 0.8472570056442942, + "x": 9.367379517285903, + "y": 1.9411018353840075, + "heading": -4.818491658640497e-18, + "velocityX": 0.07175126031593472, + "velocityY": 2.294054442177298, + "angularVelocity": 1.103492773996652e-17 + }, + { + "timestamp": 0.8857686877190348, + "x": 9.370268377881706, + "y": 2.0334655430346826, + "heading": -4.404491630170937e-18, + "velocityX": 0.07501257904536195, + "velocityY": 2.398329615191123, + "angularVelocity": 1.0749985878873683e-17 + }, + { + "timestamp": 0.9242803697937755, + "x": 9.373282836582714, + "y": 2.1298450627804466, + "heading": -4.0240108262658506e-18, + "velocityX": 0.07827387791466267, + "velocityY": 2.5026047825882425, + "angularVelocity": 9.879620738584363e-18 + }, + { + "timestamp": 0.9627920518685161, + "x": 9.37642289248502, + "y": 2.2302403943656666, + "heading": -3.6504323401485956e-18, + "velocityX": 0.08153515331304911, + "velocityY": 2.606879943347587, + "angularVelocity": 9.700394156725681e-18 + }, + { + "timestamp": 1.0013037339432567, + "x": 9.37968854450395, + "y": 2.3346515374835928, + "heading": -3.3103873083446697e-18, + "velocityX": 0.08479640054654522, + "velocityY": 2.7111550961418156, + "angularVelocity": 8.829659523974913e-18 + }, + { + "timestamp": 1.0398154160179973, + "x": 9.383079791313795, + "y": 2.443078491759321, + "heading": -3.0038939088056992e-18, + "velocityX": 0.08805761335659339, + "velocityY": 2.8154302392012207, + "angularVelocity": 7.958452932319959e-18 + }, + { + "timestamp": 1.078327098092738, + "x": 9.386596631257447, + "y": 2.55552125672424, + "heading": -2.712666864172415e-18, + "velocityX": 0.09131878313780757, + "velocityY": 2.9197053700925846, + "angularVelocity": 7.562044502762482e-18 + }, + { + "timestamp": 1.1168387801674786, + "x": 9.390239062204358, + "y": 2.6719798317758787, + "heading": -2.455043433781108e-18, + "velocityX": 0.09457989759701421, + "velocityY": 3.023980485340122, + "angularVelocity": 6.689488102333705e-18 + }, + { + "timestamp": 1.1553504622422193, + "x": 9.394007081313857, + "y": 2.792454216110998, + "heading": -2.2066601032107886e-18, + "velocityX": 0.09784093829491186, + "velocityY": 3.1282555797306153, + "angularVelocity": 6.44955830195378e-18 + }, + { + "timestamp": 1.19386214431696, + "x": 9.397900684609104, + "y": 2.9169444086051644, + "heading": -1.933386641992854e-18, + "velocityX": 0.10110187572961327, + "velocityY": 3.2325306449239046, + "angularVelocity": 7.095859159001267e-18 + }, + { + "timestamp": 1.2323738263917006, + "x": 9.401919866125063, + "y": 3.0454504075719497, + "heading": -1.7122081073894685e-18, + "velocityX": 0.10436265827531789, + "velocityY": 3.336805666327168, + "angularVelocity": 5.743154556387858e-18 + }, + { + "timestamp": 1.2708855084664412, + "x": 9.406064615920602, + "y": 3.1779722102012298, + "heading": -1.476155173514594e-18, + "velocityX": 0.10762318268827334, + "velocityY": 3.441080614762319, + "angularVelocity": 6.129385437640386e-18 + }, + { + "timestamp": 1.3093971905411819, + "x": 9.410334914115749, + "y": 3.3145098108749202, + "heading": -1.2376298640724743e-18, + "velocityX": 0.110883190894905, + "velocityY": 3.545355417317451, + "angularVelocity": 6.1935835205216205e-18 + }, + { + "timestamp": 1.3479088726159225, + "x": 9.414730701089338, + "y": 3.4550631927552793, + "heading": 2.8326472990512134e-19, + "velocityX": 0.11414165096994072, + "velocityY": 3.6496297826613113, + "angularVelocity": 3.9491773945227515e-17 + }, + { + "timestamp": 1.3864205546906632, + "x": 9.416487602702174, + "y": 3.594033329865462, + "heading": 2.0824247764857095e-19, + "velocityX": 0.0456199656347806, + "velocityY": 3.608519016138527, + "angularVelocity": -1.948038506847508e-18 + }, + { + "timestamp": 1.4249322367654038, + "x": 9.418118779161949, + "y": 3.72898769314333, + "heading": 1.2837991956347999e-19, + "velocityX": 0.04235536782269175, + "velocityY": 3.5042448422782067, + "angularVelocity": -2.073722649094852e-18 + }, + { + "timestamp": 1.4634439188401445, + "x": 9.419624288998323, + "y": 3.859926262067809, + "heading": 8.114065042866733e-20, + "velocityX": 0.039092289800198535, + "velocityY": 3.399970135564655, + "angularVelocity": -1.2266214983339523e-18 + }, + { + "timestamp": 1.5019556009148851, + "x": 9.421004151718188, + "y": 3.9868490297914985, + "heading": 4.235807718061273e-20, + "velocityX": 0.03582971829639282, + "velocityY": 3.2956952510504913, + "angularVelocity": -1.0070336999424748e-18 + }, + { + "timestamp": 1.5404672829896258, + "x": 9.422258377075195, + "y": 4.109755992889404, + "heading": 0, + "velocityX": 0.032567400057303936, + "velocityY": 3.19142027760242, + "angularVelocity": -1.099875807928052e-18 + }, + { + "timestamp": 1.5728708853392595, + "x": 9.424747642519675, + "y": 4.2107130428092905, + "heading": -1.4040882525966132e-20, + "velocityX": 0.07682063918758748, + "velocityY": 3.1156119258149833, + "angularVelocity": -4.3331207807652294e-19 + }, + { + "timestamp": 1.6052744876888931, + "x": 9.428378265685053, + "y": 4.30906475724215, + "heading": -1.1819913684396256e-20, + "velocityX": 0.11204381309845972, + "velocityY": 3.0352092761677727, + "angularVelocity": 6.854112197807745e-20 + }, + { + "timestamp": 1.6376780900385268, + "x": 9.432897595673024, + "y": 4.404714495874338, + "heading": 2.3349695483900227e-21, + "velocityX": 0.1394699866764316, + "velocityY": 2.9518242323841037, + "angularVelocity": 4.368308637354792e-19 + }, + { + "timestamp": 1.6700816923881605, + "x": 9.438091279218941, + "y": 4.497600953370514, + "heading": 2.4915089595540556e-20, + "velocityX": 0.1602810542444682, + "velocityY": 2.8665472589724654, + "angularVelocity": 6.968401212937426e-19 + }, + { + "timestamp": 1.7024852947377942, + "x": 9.443778467028542, + "y": 4.5876861734749, + "heading": 5.304419057485532e-20, + "velocityX": 0.1755109740033915, + "velocityY": 2.780098926420832, + "angularVelocity": 8.680859138130865e-19 + }, + { + "timestamp": 1.7348888970874279, + "x": 9.4498063984981, + "y": 4.674947500361938, + "heading": 8.434161630297136e-20, + "velocityX": 0.1860265844678467, + "velocityY": 2.6929514177310208, + "angularVelocity": 9.658628285962778e-19 + }, + { + "timestamp": 1.7672924994370616, + "x": 9.456045423647167, + "y": 4.759372294130309, + "heading": 1.1680908657410498e-19, + "velocityX": 0.19254109718263593, + "velocityY": 2.6054138320002553, + "angularVelocity": 1.0019712819026323e-18 + }, + { + "timestamp": 1.7996961017866953, + "x": 9.462384788164714, + "y": 4.840954480993348, + "heading": 1.261900827710795e-19, + "velocityX": 0.1956376469858513, + "velocityY": 2.5176888045585115, + "angularVelocity": 2.8950495381581065e-19 + }, + { + "timestamp": 1.832099704136329, + "x": 9.468729194239346, + "y": 4.919692294857876, + "heading": 1.3490263100448028e-19, + "velocityX": 0.1957932333009324, + "velocityY": 2.429909274127901, + "angularVelocity": 2.688761178225079e-19 + }, + { + "timestamp": 1.8645033064859626, + "x": 9.474996039144651, + "y": 4.9955867887508845, + "heading": 1.3028928235433524e-19, + "velocityX": 0.19339963617894118, + "velocityY": 2.3421622409172134, + "angularVelocity": -1.42371308032916e-19 + }, + { + "timestamp": 1.8969069088355963, + "x": 9.48111320970876, + "y": 5.068640845584036, + "heading": 1.2133559071887303e-19, + "velocityX": 0.188780571311318, + "velocityY": 2.2545041765696707, + "angularVelocity": -2.763176447663805e-19 + }, + { + "timestamp": 1.92931051118523, + "x": 9.487017319760973, + "y": 5.138858515433651, + "heading": 1.0707275159759722e-19, + "velocityX": 0.1822053606419894, + "velocityY": 2.166971100680984, + "angularVelocity": -4.401620322213563e-19 + }, + { + "timestamp": 1.9617141135348637, + "x": 9.49265229621183, + "y": 5.206244568479539, + "heading": 2.2241510805607453e-20, + "velocityX": 0.17389969146195045, + "velocityY": 2.079585236196706, + "angularVelocity": -2.6179570889795982e-18 + }, + { + "timestamp": 1.9941177158844974, + "x": 9.49796823847145, + "y": 5.270804191896735, + "heading": -6.952468961730891e-20, + "velocityX": 0.16405405183849694, + "velocityY": 1.992359451909064, + "angularVelocity": -2.831975287500493e-18 + }, + { + "timestamp": 2.0265213182341313, + "x": 9.50292049238692, + "y": 5.332542783830851, + "heading": -2.2622195221612505e-19, + "velocityX": 0.15283035083673954, + "velocityY": 1.9053002585317274, + "angularVelocity": -4.835797721349406e-18 + }, + { + "timestamp": 2.058924920583765, + "x": 9.507468893167124, + "y": 5.391465813474863, + "heading": -1.8882276010757942e-19, + "velocityX": 0.1403671336021788, + "velocityY": 1.8184098486407023, + "angularVelocity": 1.1541678128651725e-18 + }, + { + "timestamp": 2.0913285229333987, + "x": 9.51157714213314, + "y": 5.447578726533896, + "heading": -1.6023011535688134e-19, + "velocityX": 0.12678371131977367, + "velocityY": 1.731687497383078, + "angularVelocity": 8.823909099626407e-19 + }, + { + "timestamp": 2.1237321252830323, + "x": 9.515212290099717, + "y": 5.5008868820776256, + "heading": -1.4095626507013954e-19, + "velocityX": 0.11218345193084106, + "velocityY": 1.645130531122315, + "angularVelocity": 5.948057382360047e-19 + }, + { + "timestamp": 2.156135727632666, + "x": 9.518344306276155, + "y": 5.551395511219431, + "heading": -2.248024505790623e-19, + "velocityX": 0.09665641932782838, + "velocityY": 1.5587350010291767, + "angularVelocity": -2.5875577312700087e-18 + }, + { + "timestamp": 2.1885393299822997, + "x": 9.5209457162136, + "y": 5.599109691031203, + "heading": -3.188656274851271e-19, + "velocityX": 0.08028150417891033, + "velocityY": 1.4724961532652485, + "angularVelocity": -2.9028619499481455e-18 + }, + { + "timestamp": 2.2209429323319334, + "x": 9.522991295869932, + "y": 5.644034329110968, + "heading": -4.891966679502781e-19, + "velocityX": 0.0631281557606156, + "velocityY": 1.386408757737169, + "angularVelocity": -5.256546776096603e-18 + }, + { + "timestamp": 2.253346534681567, + "x": 9.524457811581927, + "y": 5.686174155592809, + "heading": -6.705056202157354e-19, + "velocityX": 0.045257798690727956, + "velocityY": 1.3004673377716809, + "angularVelocity": -5.595333582626272e-18 + }, + { + "timestamp": 2.285750137031201, + "x": 9.525323797829595, + "y": 5.725533720335378, + "heading": -6.435565832114582e-19, + "velocityX": 0.026724999224586724, + "velocityY": 1.214666329930906, + "angularVelocity": 8.316679571589788e-19 + }, + { + "timestamp": 2.3181537393808345, + "x": 9.525569366301788, + "y": 5.762117393684421, + "heading": -6.282377661829914e-19, + "velocityX": 0.007578431235604929, + "velocityY": 1.1290001943088244, + "angularVelocity": 4.727504195076832e-19 + }, + { + "timestamp": 2.350557341730468, + "x": 9.525176041038433, + "y": 5.795929369667312, + "heading": -6.248418889518024e-19, + "velocityX": -0.012138319039683754, + "velocityY": 1.043463489585527, + "angularVelocity": 1.0479932342819168e-19 + }, + { + "timestamp": 2.382960944080102, + "x": 9.524126615418227, + "y": 5.826973670804758, + "heading": -6.3364197761870355e-19, + "velocityX": -0.032386078834140526, + "velocityY": 0.9580509229337928, + "angularVelocity": -2.715775677311782e-19 + }, + { + "timestamp": 2.4153645464297355, + "x": 9.522405027544709, + "y": 5.855254153957586, + "heading": -6.548936006090998e-19, + "velocityX": -0.0531295210619789, + "velocityY": 0.8727573819627032, + "angularVelocity": -6.558414967128584e-19 + }, + { + "timestamp": 2.447768148779369, + "x": 9.519996251206273, + "y": 5.880774516793202, + "heading": -6.888362196158089e-19, + "velocityX": -0.07433668369481979, + "velocityY": 0.7875779538414581, + "angularVelocity": -1.047495397394818e-18 + }, + { + "timestamp": 2.480171751129003, + "x": 9.516886200083079, + "y": 5.9035383045762275, + "heading": -5.506007832682073e-19, + "velocityX": -0.09597856095246612, + "velocityY": 0.7025079353031433, + "angularVelocity": 4.26605150961703e-18 + }, + { + "timestamp": 2.5125753534786366, + "x": 9.513061643273414, + "y": 5.923548917074331, + "heading": -5.043259035657883e-19, + "velocityX": -0.11802875397613825, + "velocityY": 0.6175428362004514, + "angularVelocity": 1.4280781303800316e-18 + }, + { + "timestamp": 2.5449789558282703, + "x": 9.508510130534903, + "y": 5.940809615433076, + "heading": -4.7137835362947e-19, + "velocityX": -0.14046317102031355, + "velocityY": 0.5326783785488524, + "angularVelocity": 1.0167864816487845e-18 + }, + { + "timestamp": 2.577382558177904, + "x": 9.503219925898293, + "y": 5.955323528919038, + "heading": -4.519466372685079e-19, + "velocityX": -0.1632597690691616, + "velocityY": 0.4479104924618523, + "angularVelocity": 5.996774606395658e-19 + }, + { + "timestamp": 2.6097861605275376, + "x": 9.49717994852565, + "y": 5.967093661463571, + "heading": -4.462088381994008e-19, + "velocityX": -0.1863983302680957, + "velocityY": 0.36323530999837034, + "angularVelocity": 1.7707267952265156e-19 + }, + { + "timestamp": 2.6421897628771713, + "x": 9.490379719860622, + "y": 5.976122897963523, + "heading": -4.543338183787842e-19, + "velocityX": -0.20986026774601668, + "velocityY": 0.2786491576623603, + "angularVelocity": -2.507433513307693e-19 + }, + { + "timestamp": 2.674593365226805, + "x": 9.48280931626334, + "y": 5.982414010312601, + "heading": -4.764815671962873e-19, + "velocityX": -0.2336284563548335, + "velocityY": 0.1941485480903284, + "angularVelocity": -6.834966224725472e-19 + }, + { + "timestamp": 2.7069969675764387, + "x": 9.47445932644268, + "y": 5.985969663149571, + "heading": -5.128041449919727e-19, + "velocityX": -0.2576870846199469, + "velocityY": 0.10973017131256312, + "angularVelocity": -1.1209427475481004e-18 + }, + { + "timestamp": 2.7394005699260724, + "x": 9.465320813098467, + "y": 5.986792419318408, + "heading": -4.5098715503885855e-19, + "velocityX": -0.282021524817208, + "velocityY": 0.02539088586384956, + "angularVelocity": 1.9077196088656083e-18 + }, + { + "timestamp": 2.771804172275706, + "x": 9.455385278269853, + "y": 5.984884745041843, + "heading": -2.8602806089077776e-19, + "velocityX": -0.30661821859834004, + "velocityY": -0.058872290061494546, + "angularVelocity": 5.090764079296635e-18 + }, + { + "timestamp": 2.8042077746253398, + "x": 9.44464463195612, + "y": 5.980249014814116, + "heading": -1.3565733993611353e-19, + "velocityX": -0.3314645760012335, + "velocityY": -0.1430621872749743, + "angularVelocity": 4.640555662244342e-18 + }, + { + "timestamp": 2.8366113769749735, + "x": 9.433091163635254, + "y": 5.9728875160217285, + "heading": 0, + "velocityX": -0.35654888602214, + "velocityY": -0.22718149398816284, + "angularVelocity": 4.186489407727029e-18 + }, + { + "timestamp": 2.8898593064936966, + "x": 9.407507023330087, + "y": 5.956859606510648, + "heading": 1.6012272048785258e-19, + "velocityX": -0.48047202091060703, + "velocityY": -0.30100530961387933, + "angularVelocity": 3.0071165753743872e-18 + }, + { + "timestamp": 2.9431072360124197, + "x": 9.37532475203567, + "y": 5.936899860175698, + "heading": 2.1188176174280419e-19, + "velocityX": -0.6043854021234748, + "velocityY": -0.3748454919346753, + "angularVelocity": 9.720385830700054e-19 + }, + { + "timestamp": 2.996355165531143, + "x": 9.336544934923388, + "y": 5.913007295411148, + "heading": 1.969629201732152e-19, + "velocityX": -0.7282877937750748, + "velocityY": -0.4487041088827337, + "angularVelocity": -2.8017677957318397e-19 + }, + { + "timestamp": 3.049603095049866, + "x": 9.291168236326735, + "y": 5.885180798221746, + "heading": -5.69918739629597e-19, + "velocityX": -0.8521777091952178, + "velocityY": -0.522583646742897, + "angularVelocity": -1.4402092419953408e-17 + }, + { + "timestamp": 3.102851024568589, + "x": 9.23919541697011, + "y": 5.853419093502993, + "heading": -9.887646126362287e-19, + "velocityX": -0.9760533381556034, + "velocityY": -0.5964871311584838, + "angularVelocity": -7.865955543786426e-18 + }, + { + "timestamp": 3.1560989540873123, + "x": 9.180627356588191, + "y": 5.817720707366942, + "heading": -1.4823749754006185e-18, + "velocityX": -1.0999124456346128, + "velocityY": -0.6704182952972421, + "angularVelocity": -9.270037591446577e-18 + }, + { + "timestamp": 3.2093468836060355, + "x": 9.115465084222988, + "y": 5.778083916728607, + "heading": -2.054357388107318e-18, + "velocityX": -1.2237522276296537, + "velocityY": -0.7443818190977213, + "angularVelocity": -1.074186987525422e-17 + }, + { + "timestamp": 3.2625948131247586, + "x": 9.043709819758144, + "y": 5.734506680271107, + "heading": -2.7089851843439773e-18, + "velocityX": -1.34756910012082, + "velocityY": -0.8183836789781219, + "angularVelocity": -1.2293955666979117e-17 + }, + { + "timestamp": 3.3158427426434818, + "x": 8.96536303243276, + "y": 5.6869865413172445, + "heading": -3.031687342340883e-18, + "velocityX": -1.4713583801945858, + "velocityY": -0.8924316754354307, + "angularVelocity": -6.060368156692205e-18 + }, + { + "timestamp": 3.369090672162205, + "x": 8.880426525998846, + "y": 5.635520486698401, + "heading": -2.954956262751476e-18, + "velocityX": -1.5951137856739797, + "velocityY": -0.9665362594191681, + "angularVelocity": 1.4410169410596809e-18 + }, + { + "timestamp": 3.422338601680928, + "x": 8.788902567634885, + "y": 5.580104733519928, + "heading": -2.8096198996615185e-18, + "velocityX": -1.7188266133761843, + "velocityY": -1.0407118864403515, + "angularVelocity": 2.729429230220988e-18 + }, + { + "timestamp": 3.475586531199651, + "x": 8.690794092860108, + "y": 5.520734391034758, + "heading": -2.444203489232445e-18, + "velocityX": -1.8424843118131036, + "velocityY": -1.114979362048128, + "angularVelocity": 6.862548144238517e-18 + }, + { + "timestamp": 3.5288344607183744, + "x": 8.586105052135341, + "y": 5.457402890506253, + "heading": -1.78509297458333e-18, + "velocityX": -1.9660678203075501, + "velocityY": -1.1893701990090748, + "angularVelocity": 1.2378145100294227e-17 + }, + { + "timestamp": 3.5820823902370975, + "x": 8.474841047191472, + "y": 5.39010094286798, + "heading": -1.7926897958080077e-18, + "velocityX": -2.089546127887395, + "velocityY": -1.2639354853151212, + "angularVelocity": -1.4266697089259563e-19 + }, + { + "timestamp": 3.6353303197558207, + "x": 8.357010639749344, + "y": 5.318814407701335, + "heading": -1.5556843330116533e-18, + "velocityX": -2.2128636457253266, + "velocityY": -1.3387663297138852, + "angularVelocity": 4.450981660874935e-18 + }, + { + "timestamp": 3.688578249274544, + "x": 8.232628539321633, + "y": 5.243519150108811, + "heading": -7.118729576928097e-19, + "velocityX": -2.335904917842405, + "velocityY": -1.4140504292480984, + "angularVelocity": 1.5846840684725827e-17 + }, + { + "timestamp": 3.741826178793267, + "x": 8.1017259282265, + "y": 5.164164657780524, + "heading": 5.54294098791122e-19, + "velocityX": -2.4583605837500735, + "velocityY": -1.490283153646069, + "angularVelocity": 2.377871119104557e-17 + }, + { + "timestamp": 3.79507410831199, + "x": 7.964413173666446, + "y": 5.080578830515485, + "heading": 5.745487949551461e-19, + "velocityX": -2.578743545545228, + "velocityY": -1.5697479323707426, + "angularVelocity": 3.8037946752418803e-19 + }, + { + "timestamp": 3.8483220378307132, + "x": 7.834386570789792, + "y": 4.9994228629449955, + "heading": 6.345872549710333e-19, + "velocityX": -2.4419090855154173, + "velocityY": -1.5241149900852726, + "angularVelocity": 1.127523761469392e-18 + }, + { + "timestamp": 3.9015699673494364, + "x": 7.711094579965497, + "y": 4.921960039014121, + "heading": 3.1385402523746345e-19, + "velocityX": -2.3154325799830713, + "velocityY": -1.454757483173811, + "angularVelocity": -6.023395532446379e-18 + }, + { + "timestamp": 3.9548178968681595, + "x": 7.5944798531964945, + "y": 4.848293085659303, + "heading": -5.504264105297611e-19, + "velocityX": -2.190033074018357, + "velocityY": -1.3834707569036095, + "angularVelocity": -1.6231250991360332e-17 + }, + { + "timestamp": 4.008065826386883, + "x": 7.484520668230775, + "y": 4.778459970937141, + "heading": -9.581601178782412e-19, + "velocityX": -2.0650415135306908, + "velocityY": -1.3114709877612607, + "angularVelocity": -7.65727038238914e-18 + }, + { + "timestamp": 4.061313755905606, + "x": 7.381205602053184, + "y": 4.71248046175784, + "heading": -1.4648466714460738e-18, + "velocityX": -1.94026447810076, + "velocityY": -1.2390999946035701, + "angularVelocity": -9.515611861125773e-18 + }, + { + "timestamp": 4.114561685424329, + "x": 7.28452761021566, + "y": 4.650366680934777, + "heading": -1.6254449722260528e-18, + "velocityX": -1.8156197379191947, + "velocityY": -1.1665013341264656, + "angularVelocity": -3.016049458842738e-18 + }, + { + "timestamp": 4.167809614943052, + "x": 7.194481914315111, + "y": 4.592126822746646, + "heading": -1.4228313180181299e-18, + "velocityX": -1.6910647364962277, + "velocityY": -1.0937487844978486, + "angularVelocity": 3.805097285489222e-18 + }, + { + "timestamp": 4.221057544461775, + "x": 7.111065060119478, + "y": 4.537766796263652, + "heading": -1.2643706503290093e-18, + "velocityX": -1.5665746058032446, + "velocityY": -1.0208852620998259, + "angularVelocity": 2.975901875587679e-18 + }, + { + "timestamp": 4.274305473980498, + "x": 7.034274434143014, + "y": 4.487291064295607, + "heading": -7.210191645961071e-19, + "velocityX": -1.4421335565632167, + "velocityY": -0.9479379278080052, + "angularVelocity": 1.0204178839174677e-17 + }, + { + "timestamp": 4.327553403499222, + "x": 6.964107990003666, + "y": 4.440703116458126, + "heading": -9.013376647533111e-19, + "velocityX": -1.3177309385273974, + "velocityY": -0.8749250582804436, + "angularVelocity": -3.3863949737865667e-18 + }, + { + "timestamp": 4.380801333017945, + "x": 6.9005640819078415, + "y": 4.398005756206596, + "heading": -6.836090002944485e-19, + "velocityX": -1.193359228615281, + "velocityY": -0.801859539656196, + "angularVelocity": 4.088959478659132e-18 + }, + { + "timestamp": 4.434049262536668, + "x": 6.843641357513053, + "y": 4.359201285097782, + "heading": -4.827360221656651e-19, + "velocityX": -1.0690129157937158, + "velocityY": -0.7287507976280857, + "angularVelocity": 3.772408486667274e-18 + }, + { + "timestamp": 4.487297192055391, + "x": 6.793338685868074, + "y": 4.324291626496749, + "heading": 1.250178093016813e-19, + "velocityX": -0.9446878423186736, + "velocityY": -0.6556059346637725, + "angularVelocity": 1.1413660606865953e-17 + }, + { + "timestamp": 4.540545121574114, + "x": 6.749655107161122, + "y": 4.293278411715859, + "heading": 7.233486990776333e-19, + "velocityX": -0.8203807941788867, + "velocityY": -0.5824304355343005, + "angularVelocity": 1.1236697086483106e-17 + }, + { + "timestamp": 4.593793051092837, + "x": 6.7125897966065144, + "y": 4.266163041840482, + "heading": 1.3151864719949234e-18, + "velocityX": -0.6960892355743994, + "velocityY": -0.509228623919408, + "angularVelocity": 1.1114755884317254e-17 + }, + { + "timestamp": 4.6470409806115605, + "x": 6.682142037824221, + "y": 4.242946733254192, + "heading": 1.4833598477443198e-18, + "velocityX": -0.5718111306391168, + "velocityY": -0.43600396853225964, + "angularVelocity": 3.1583083402507556e-18 + }, + { + "timestamp": 4.700288910130284, + "x": 6.65831120278551, + "y": 4.223630551903339, + "heading": 1.64981294853882e-18, + "velocityX": -0.4475448201292212, + "velocityY": -0.36275929459493594, + "angularVelocity": 3.1260014476336314e-18 + }, + { + "timestamp": 4.753536839649007, + "x": 6.641096736417822, + "y": 4.208215439579853, + "heading": 1.3968003826691399e-18, + "velocityX": -0.3232889339224929, + "velocityY": -0.2894969337364861, + "angularVelocity": -4.7515940065872536e-18 + }, + { + "timestamp": 4.80678476916773, + "x": 6.630498144590057, + "y": 4.196702234418521, + "heading": 7.260749450146028e-19, + "velocityX": -0.19904232753385848, + "velocityY": -0.21621883264557085, + "angularVelocity": -1.2596271848649556e-17 + }, + { + "timestamp": 4.860032698686453, + "x": 6.626514984598739, + "y": 4.189091687117633, + "heading": 4.786365666958557e-19, + "velocityX": -0.07480403514876906, + "velocityY": -0.14292663338602665, + "angularVelocity": -4.6469100159348216e-18 + }, + { + "timestamp": 4.913280628205176, + "x": 6.629146857536548, + "y": 4.185384473943056, + "heading": 2.3618468980917354e-19, + "velocityX": 0.04942676572774048, + "velocityY": -0.06962173380419516, + "angularVelocity": -4.553263539134624e-18 + }, + { + "timestamp": 4.966528557723899, + "x": 6.638393402099609, + "y": 4.185581207275391, + "heading": 0, + "velocityX": 0.17365078129113545, + "velocityY": 0.0036946663299880058, + "angularVelocity": -4.435565056192453e-18 + }, + { + "timestamp": 5.028339052223556, + "x": 6.659476247359193, + "y": 4.185879969977683, + "heading": -2.458396276404072e-19, + "velocityX": 0.34108844186160825, + "velocityY": 0.00483352713338811, + "angularVelocity": -3.9773122639999994e-18 + }, + { + "timestamp": 5.090149546723213, + "x": 6.690908497115958, + "y": 4.186249126225705, + "heading": -4.794739448057151e-19, + "velocityX": 0.5085261008054116, + "velocityY": 0.005972387877019005, + "angularVelocity": -3.779848850849013e-18 + }, + { + "timestamp": 5.151960041222869, + "x": 6.73269015125753, + "y": 4.186688676015329, + "heading": -7.009030331817381e-19, + "velocityX": 0.6759637579311725, + "velocityY": 0.007111248553858993, + "angularVelocity": -3.582386770179082e-18 + }, + { + "timestamp": 5.213770535722526, + "x": 6.784821209657488, + "y": 4.187198619341911, + "heading": -9.10126991100271e-19, + "velocityX": 0.8434014130116355, + "velocityY": 0.008250109155574243, + "angularVelocity": -3.3849262788686062e-18 + }, + { + "timestamp": 5.275581030222183, + "x": 6.847301672172556, + "y": 4.18777895620019, + "heading": -1.1071459324547749e-18, + "velocityX": 1.010839065774094, + "velocityY": 0.00938896967216917, + "angularVelocity": -3.187467628455642e-18 + }, + { + "timestamp": 5.3373915247218395, + "x": 6.920131538638988, + "y": 4.188429686584155, + "heading": -1.3138363613465469e-18, + "velocityX": 1.1782767158874046, + "velocityY": 0.01052783009151207, + "angularVelocity": -3.343937620344753e-18 + }, + { + "timestamp": 5.399202019221496, + "x": 7.003310808867847, + "y": 4.189150810486871, + "heading": -1.5083220359631332e-18, + "velocityX": 1.3457143629440058, + "velocityY": 0.011666690398678441, + "angularVelocity": -3.14648320673789e-18 + }, + { + "timestamp": 5.461012513721153, + "x": 7.096839482638708, + "y": 4.189942327900254, + "heading": -1.6778418861102721e-18, + "velocityX": 1.5131520064344455, + "velocityY": 0.01280555057502086, + "angularVelocity": -2.742574040198153e-18 + }, + { + "timestamp": 5.52282300822081, + "x": 7.200717559691066, + "y": 4.19080423881475, + "heading": -1.8212468135453705e-18, + "velocityX": 1.6805896457103302, + "velocityY": 0.013944410596816349, + "angularVelocity": -2.3200742045641136e-18 + }, + { + "timestamp": 5.584633502720466, + "x": 7.314945039712318, + "y": 4.1917365432189, + "heading": -1.9371340770567474e-18, + "velocityX": 1.8480272799287492, + "velocityY": 0.015083270433237763, + "angularVelocity": -1.8748801503066307e-18 + }, + { + "timestamp": 5.646443997220123, + "x": 7.43952192232039, + "y": 4.1927392410987085, + "heading": -2.0408174233321747e-18, + "velocityX": 2.01546490796582, + "velocityY": 0.016222130043198665, + "angularVelocity": -1.6774392811054847e-18 + }, + { + "timestamp": 5.70825449171978, + "x": 7.574448207037693, + "y": 4.193812332436685, + "heading": -2.1131553651126336e-18, + "velocityX": 2.1829025282762045, + "velocityY": 0.017360989370227026, + "angularVelocity": -1.1703181963552742e-18 + }, + { + "timestamp": 5.770064986219436, + "x": 7.7197238932501815, + "y": 4.194955817210358, + "heading": -2.195166575952037e-18, + "velocityX": 2.350340138652278, + "velocityY": 0.018499848333678435, + "angularVelocity": -1.326817010497694e-18 + }, + { + "timestamp": 5.831875480719093, + "x": 7.8753489801391305, + "y": 4.196169695389781, + "heading": -2.264975230718563e-18, + "velocityX": 2.517777735782602, + "velocityY": 0.019638706812628887, + "angularVelocity": -1.129398162801884e-18 + }, + { + "timestamp": 5.89368597521875, + "x": 8.041323466558321, + "y": 4.1974539669330495, + "heading": -2.3072687042707436e-18, + "velocityX": 2.6852153143688753, + "velocityY": 0.020777564613663587, + "angularVelocity": -6.842442749279986e-19 + }, + { + "timestamp": 5.9554964697184065, + "x": 8.21764735078843, + "y": 4.198808631777348, + "heading": -2.337361894093645e-18, + "velocityX": 2.8526528651390715, + "velocityY": 0.02191642139840774, + "angularVelocity": -4.868621941767107e-19 + }, + { + "timestamp": 6.017306964218063, + "x": 8.404320629963914, + "y": 4.200233689818039, + "heading": -2.355180833690065e-18, + "velocityX": 3.0200903695491412, + "velocityY": 0.02305527649028737, + "angularVelocity": -2.8828343845164218e-19 + }, + { + "timestamp": 6.07911745871772, + "x": 8.601343298353688, + "y": 4.201729140845959, + "heading": -2.3608060407320693e-18, + "velocityX": 3.187527781238981, + "velocityY": 0.02419412819822115, + "angularVelocity": -9.100734554654671e-20 + }, + { + "timestamp": 6.140927953217377, + "x": 8.80871533876452, + "y": 4.203294984233899, + "heading": -2.3351084008043562e-18, + "velocityX": 3.3549649147683756, + "velocityY": 0.02533296975887398, + "angularVelocity": 4.157487894925156e-19 + }, + { + "timestamp": 6.202738447717033, + "x": 9.015703343151486, + "y": 4.204702859409942, + "heading": -2.1446820364753337e-18, + "velocityX": 3.3487517946991447, + "velocityY": 0.022777283816251635, + "angularVelocity": 3.0808101776722092e-18 + }, + { + "timestamp": 6.26454894221669, + "x": 9.212341975531281, + "y": 4.2060403401824225, + "heading": -2.0047712820216723e-18, + "velocityX": 3.1813146613943504, + "velocityY": 0.021638409194230757, + "angularVelocity": 2.263543788726926e-18 + }, + { + "timestamp": 6.326359436716347, + "x": 9.398631218703736, + "y": 4.207307426944435, + "heading": -1.8387963261016747e-18, + "velocityX": 3.0138772498170407, + "velocityY": 0.02049954093181682, + "angularVelocity": 2.685223022395206e-18 + }, + { + "timestamp": 6.388169931216003, + "x": 9.574571066935462, + "y": 4.208504119827007, + "heading": -1.672275264354956e-18, + "velocityX": 2.8464397454821033, + "velocityY": 0.019360674789277475, + "angularVelocity": 2.694058180497591e-18 + }, + { + "timestamp": 6.44998042571566, + "x": 9.740161517359757, + "y": 4.209630418895655, + "heading": -1.4988253948477009e-18, + "velocityX": 2.6790021947683296, + "velocityY": 0.01822180970667645, + "angularVelocity": 2.8061557828406487e-18 + }, + { + "timestamp": 6.511790920215317, + "x": 9.895402568256603, + "y": 4.210686324189689, + "heading": -1.3682141824071403e-18, + "velocityX": 2.511564616227247, + "velocityY": 0.01708294526003873, + "angularVelocity": 2.113091300836739e-18 + }, + { + "timestamp": 6.5736014147149735, + "x": 10.040294218479321, + "y": 4.211671835735315, + "heading": -1.2370525990388503e-18, + "velocityX": 2.344127019134622, + "velocityY": 0.015944081237376676, + "angularVelocity": 2.121995457706308e-18 + }, + { + "timestamp": 6.63541190921463, + "x": 10.17483646720885, + "y": 4.2125869535512495, + "heading": -1.1181012652869172e-18, + "velocityX": 2.176689408790894, + "velocityY": 0.01480521751755444, + "angularVelocity": 1.9244521449458323e-18 + }, + { + "timestamp": 6.697222403714287, + "x": 10.299029313830903, + "y": 4.213431677651533, + "heading": -9.730760684704942e-19, + "velocityX": 2.0092517885088386, + "velocityY": 0.0136663540248621, + "angularVelocity": 2.34628768825949e-18 + }, + { + "timestamp": 6.759032898213944, + "x": 10.41287275786769, + "y": 4.214206008047086, + "heading": -8.232453614546966e-19, + "velocityX": 1.841814160496972, + "velocityY": 0.012527490708826364, + "angularVelocity": 2.4240335458871123e-18 + }, + { + "timestamp": 6.8208433927136, + "x": 10.51636679893699, + "y": 4.214909944746641, + "heading": -7.315642270842732e-19, + "velocityX": 1.6743765263012564, + "velocityY": 0.01138862753411592, + "angularVelocity": 1.4832616817746723e-18 + }, + { + "timestamp": 6.882653887213257, + "x": 10.609511436726066, + "y": 4.2155434877573486, + "heading": -6.381706774047405e-19, + "velocityX": 1.5069388870460279, + "velocityY": 0.010249764475035264, + "angularVelocity": 1.5109659573711873e-18 + }, + { + "timestamp": 6.944464381712914, + "x": 10.692306670974313, + "y": 4.216106637085162, + "heading": -5.442244989502098e-19, + "velocityX": 1.3395012435745384, + "velocityY": 0.009110901512312773, + "angularVelocity": 1.5199066466431908e-18 + }, + { + "timestamp": 7.00627487621257, + "x": 10.764752501461214, + "y": 4.216599392735122, + "heading": -4.624869062138984e-19, + "velocityX": 1.1720635965354431, + "velocityY": 0.007972038631124114, + "angularVelocity": 1.3223902486576805e-18 + }, + { + "timestamp": 7.068085370712227, + "x": 10.826848927997757, + "y": 4.217021754711548, + "heading": -3.710813756426528e-19, + "velocityX": 1.0046259464384006, + "velocityY": 0.006833175819821598, + "angularVelocity": 1.4788028118852417e-18 + }, + { + "timestamp": 7.129895865211884, + "x": 10.878595950420129, + "y": 4.217373723018184, + "heading": -3.02154183325193e-19, + "velocityX": 0.8371882936911367, + "velocityY": 0.005694313069087075, + "angularVelocity": 1.11513740490256e-18 + }, + { + "timestamp": 7.1917063597115405, + "x": 10.919993568584998, + "y": 4.217655297658306, + "heading": -2.262930091186312e-19, + "velocityX": 0.6697506386249291, + "velocityY": 0.004555450371349547, + "angularVelocity": 1.227318712671864e-18 + }, + { + "timestamp": 7.253516854211197, + "x": 10.951041782365888, + "y": 4.217866478634804, + "heading": -1.4462413004463968e-19, + "velocityX": 0.5023129815125947, + "velocityY": 0.003416587720374073, + "angularVelocity": 1.3212785667213008e-18 + }, + { + "timestamp": 7.315327348710854, + "x": 10.97174059165038, + "y": 4.218007265950247, + "heading": -5.814834591741866e-20, + "velocityX": 0.33487532258148117, + "velocityY": 0.00227772511096487, + "angularVelocity": 1.3990469909142111e-18 + }, + { + "timestamp": 7.377137843210511, + "x": 10.98208999633789, + "y": 4.218077659606934, + "heading": 0, + "velocityX": 0.16743766202303859, + "velocityY": 0.0011388625387465416, + "angularVelocity": 9.407520175646076e-19 + }, + { + "timestamp": 7.438948337710167, + "x": 10.98208999633789, + "y": 4.218077659606934, + "heading": 0, + "velocityX": 6.325612915616031e-33, + "velocityY": -2.0300544405243873e-31, + "angularVelocity": 0 + } + ] + }, + "9": { + "waypoints": [ + { + "x": 9.487251281738281, + "y": 1.0334224700927734, + "heading": 0, + "velocityMagnitude": 0, + "velocityAngle": 1.5872783360152984, + "translationConstrained": true, + "headingConstrained": true, + "velocityMagnitudeConstrained": true, + "velocityAngleConstrained": true, + "angularVelocity": 0, + "angularVelocityConstrained": true, + "controlIntervalCount": 0 + }, + { + "x": 9.443922996520996, + "y": 4.337231159210205, + "heading": 0, + "velocityMagnitude": 0, + "velocityAngle": 1.5639473253351956, + "translationConstrained": true, + "headingConstrained": true, + "velocityMagnitudeConstrained": false, + "velocityAngleConstrained": true, + "angularVelocity": 0, + "angularVelocityConstrained": false, + "controlIntervalCount": 0 + }, + { + "x": 9.443922996520996, + "y": 5.182139873504639, + "heading": 0, + "velocityMagnitude": 0, + "velocityAngle": 2.3847582198426744, + "translationConstrained": true, + "headingConstrained": true, + "velocityMagnitudeConstrained": false, + "velocityAngleConstrained": true, + "angularVelocity": 0, + "angularVelocityConstrained": false, + "controlIntervalCount": 0 + }, + { + "x": 7.158337116241455, + "y": 5.182139873504639, + "heading": 0, + "velocityMagnitude": 0, + "velocityAngle": 0, + "translationConstrained": true, + "headingConstrained": true, + "velocityMagnitudeConstrained": false, + "velocityAngleConstrained": false, + "angularVelocity": 0, + "angularVelocityConstrained": false, + "controlIntervalCount": 0 + }, + { + "x": 7.1691694259643555, + "y": 3.600644588470459, + "heading": 0, + "velocityMagnitude": 0, + "velocityAngle": 0, + "translationConstrained": true, + "headingConstrained": true, + "velocityMagnitudeConstrained": false, + "velocityAngleConstrained": false, + "angularVelocity": 0, + "angularVelocityConstrained": false, + "controlIntervalCount": 0 + }, + { + "x": 9.443922996520996, + "y": 3.6439731121063232, + "heading": 0, + "velocityMagnitude": 0, + "velocityAngle": 0, + "translationConstrained": true, + "headingConstrained": true, + "velocityMagnitudeConstrained": true, + "velocityAngleConstrained": false, + "angularVelocity": 0, + "angularVelocityConstrained": true, + "controlIntervalCount": 0 + } + ], + "trajectory": [ + { + "timestamp": 0, + "x": 9.48725128173828, + "y": 1.0334224700927734, + "heading": 2.042026558603943e-38, + "velocityX": 2.0789894429506748e-33, + "velocityY": 2.830923369396266e-32, + "angularVelocity": 0 + }, + { + "timestamp": 0.04240564041799475, + "x": 9.4871448998338, + "y": 1.0382926456122414, + "heading": 9.943795864363938e-21, + "velocityX": -0.0025086734555163667, + "velocityY": 0.11484735217915842, + "angularVelocity": 2.3449239037314736e-19 + }, + { + "timestamp": 0.0848112808359895, + "x": 9.486932136114321, + "y": 1.0480329966093236, + "heading": 2.9830043131816505e-20, + "velocityX": -0.005017344800842892, + "velocityY": 0.22969470337132947, + "angularVelocity": 4.689530796217198e-19 + }, + { + "timestamp": 0.12721692125398426, + "x": 9.486612990676212, + "y": 1.062643523038951, + "heading": 5.965665587916088e-20, + "velocityX": -0.007526013873606992, + "velocityY": 0.3445420535006988, + "angularVelocity": 7.033644604732387e-19 + }, + { + "timestamp": 0.169622561671979, + "x": 9.486187463623557, + "y": 1.0821242248524547, + "heading": 9.942134329561084e-20, + "velocityX": -0.01003468049194515, + "velocityY": 0.4593894024823678, + "angularVelocity": 9.37721821241599e-19 + }, + { + "timestamp": 0.21202820208997375, + "x": 9.485655555069107, + "y": 1.1064751019971164, + "heading": 1.4912322566451605e-19, + "velocityX": -0.012543344451253364, + "velocityY": 0.5742367502208419, + "angularVelocity": 1.1720584352015508e-18 + }, + { + "timestamp": 0.2544338425079685, + "x": 9.48501726513543, + "y": 1.1356961544156405, + "heading": 2.0876008033417065e-19, + "velocityX": -0.015052005520230899, + "velocityY": 0.6890840966081908, + "angularVelocity": 1.4063426358296795e-18 + }, + { + "timestamp": 0.2968394829259633, + "x": 9.484272593956234, + "y": 1.1697873820455318, + "heading": 2.783254890317532e-19, + "velocityX": -0.017560663436024596, + "velocityY": 0.8039314415217913, + "angularVelocity": 1.6404754810223779e-18 + }, + { + "timestamp": 0.33924512334395807, + "x": 9.483421541677973, + "y": 1.2087487848183536, + "heading": 3.5782400363277806e-19, + "velocityX": -0.02006931789821662, + "velocityY": 0.9187787848215332, + "angularVelocity": 1.874715668970879e-18 + }, + { + "timestamp": 0.38165076376195284, + "x": 9.482464108461746, + "y": 1.2525803626588379, + "heading": 4.472535009967894e-19, + "velocityX": -0.022577968561308556, + "velocityY": 1.033626126346329, + "angularVelocity": 2.1089057880414308e-18 + }, + { + "timestamp": 0.4240564041799476, + "x": 9.48140029448562, + "y": 1.30128211548381, + "heading": 5.466053971653031e-19, + "velocityX": -0.025086615025226803, + "velocityY": 1.148473465909707, + "angularVelocity": 2.3428934825764293e-18 + }, + { + "timestamp": 0.4664620445979424, + "x": 9.480230099947454, + "y": 1.354854043200871, + "heading": 6.270895036316174e-19, + "velocityX": -0.027595256823189456, + "velocityY": 1.2633208032941787, + "angularVelocity": 1.8979577939439575e-18 + }, + { + "timestamp": 0.5088676850159372, + "x": 9.478953525068398, + "y": 1.4132961457067776, + "heading": 7.022555074979213e-19, + "velocityX": -0.03010389340600295, + "velocityY": 1.3781681382439617, + "angularVelocity": 1.772547607398775e-18 + }, + { + "timestamp": 0.5512733254339319, + "x": 9.477570570097257, + "y": 1.4766084228854086, + "heading": 7.873356000130682e-19, + "velocityX": -0.032612524121449, + "velocityY": 1.4930154704554248, + "angularVelocity": 2.006339334097056e-18 + }, + { + "timestamp": 0.5936789658519267, + "x": 9.47608123531603, + "y": 1.5447908746051997, + "heading": 8.823057726560091e-19, + "velocityX": -0.03512114818679701, + "velocityY": 1.6078627995643624, + "angularVelocity": 2.2395650064451655e-18 + }, + { + "timestamp": 0.6360846062699215, + "x": 9.474485521047026, + "y": 1.617843500715841, + "heading": 9.774794670564602e-19, + "velocityX": -0.03762976465149391, + "velocityY": 1.7227101251287322, + "angularVelocity": 2.244364461927908e-18 + }, + { + "timestamp": 0.6784902466879162, + "x": 9.472783427662161, + "y": 1.6957663010439643, + "heading": 1.0626249201373726e-18, + "velocityX": -0.04013837234549543, + "velocityY": 1.8375574466047766, + "angularVelocity": 2.0078809576964904e-18 + }, + { + "timestamp": 0.720895887105911, + "x": 9.47097495559539, + "y": 1.7785592753873969, + "heading": 1.136044401622763e-18, + "velocityX": -0.04264696980605482, + "velocityY": 1.9524047633132235, + "angularVelocity": 1.7313619299700687e-18 + }, + { + "timestamp": 0.7633015275239058, + "x": 9.469060105359615, + "y": 1.866222423507331, + "heading": 1.2193239881571744e-18, + "velocityX": -0.0451555551712103, + "velocityY": 2.0672520743901783, + "angularVelocity": 1.9638807726635784e-18 + }, + { + "timestamp": 0.8057071679419006, + "x": 9.467038877570412, + "y": 1.9587557451173774, + "heading": 1.286588431468213e-18, + "velocityX": -0.047664126019975314, + "velocityY": 2.1820993787135547, + "angularVelocity": 1.5862156816463694e-18 + }, + { + "timestamp": 0.8481128083598953, + "x": 9.464911272980254, + "y": 2.0561592398677684, + "heading": 1.3636923650301692e-18, + "velocityX": -0.05017267912366991, + "velocityY": 2.296946674788811, + "angularVelocity": 1.818248429873892e-18 + }, + { + "timestamp": 0.8905184487778901, + "x": 9.46267729252993, + "y": 2.1584329073217075, + "heading": 1.4505957234023422e-18, + "velocityX": -0.052681210041686424, + "velocityY": 2.4117939605636165, + "angularVelocity": 2.0493362812866533e-18 + }, + { + "timestamp": 0.9329240891958849, + "x": 9.460336937429323, + "y": 2.2655767469182706, + "heading": 1.5472803584359657e-18, + "velocityX": -0.05518971242820439, + "velocityY": 2.5266412331108703, + "angularVelocity": 2.2799961860839735e-18 + }, + { + "timestamp": 0.9753297296138796, + "x": 9.457890209292124, + "y": 2.377590757910745, + "heading": 1.6536466656743909e-18, + "velocityX": -0.05769817676044675, + "velocityY": 2.6414884880493084, + "angularVelocity": 2.5083071179121423e-18 + }, + { + "timestamp": 1.0177353700318743, + "x": 9.4553371103785, + "y": 2.494474939256018, + "heading": 1.743873672813524e-18, + "velocityX": -0.060206587793311304, + "velocityY": 2.7563357183893307, + "angularVelocity": 2.127714181383059e-18 + }, + { + "timestamp": 1.060141010449869, + "x": 9.452677644080838, + "y": 2.616229289394468, + "heading": 1.8274868542003677e-18, + "velocityX": -0.06271491882651421, + "velocityY": 2.8711829119507097, + "angularVelocity": 1.9717486677423863e-18 + }, + { + "timestamp": 1.1025466508678636, + "x": 9.449911816058748, + "y": 2.7428538057403618, + "heading": 1.8988600974648397e-18, + "velocityX": -0.06522311639447756, + "velocityY": 2.986030044535951, + "angularVelocity": 1.6831095364933795e-18 + }, + { + "timestamp": 1.1449522912858583, + "x": 9.447039637651764, + "y": 2.8743484831746504, + "heading": 1.9472251907105894e-18, + "velocityX": -0.0677310465524073, + "velocityY": 3.1008770564049897, + "angularVelocity": 1.1405370707587538e-18 + }, + { + "timestamp": 1.187357931703853, + "x": 9.444061143025511, + "y": 3.0107133067865663, + "heading": 1.9879182660274187e-18, + "velocityX": -0.0702381710133901, + "velocityY": 3.215723716651743, + "angularVelocity": 9.59617525698653e-19 + }, + { + "timestamp": 1.2297635721218476, + "x": 9.443464378511562, + "y": 3.148042361806912, + "heading": 1.8408102143003954e-18, + "velocityX": -0.014072762753181542, + "velocityY": 3.2384619986071734, + "angularVelocity": -3.4690697324267305e-18 + }, + { + "timestamp": 1.2721692125398423, + "x": 9.442974063870757, + "y": 3.2805012734237167, + "heading": 1.6823653317280151e-18, + "velocityX": -0.011562486454314621, + "velocityY": 3.123615403778499, + "angularVelocity": -3.736412209123864e-18 + }, + { + "timestamp": 1.314574852957837, + "x": 9.442590166523006, + "y": 3.4080900253308806, + "heading": 1.5132869376537693e-18, + "velocityX": -0.00905297846243119, + "velocityY": 3.0087684244231836, + "angularVelocity": -3.987169181689804e-18 + }, + { + "timestamp": 1.3569804933758316, + "x": 9.44231267552572, + "y": 3.5308086119494133, + "heading": 1.355336087070504e-18, + "velocityX": -0.006543728519569948, + "velocityY": 2.89392131350538, + "angularVelocity": -3.724762272283759e-18 + }, + { + "timestamp": 1.3993861337938263, + "x": 9.442141585393275, + "y": 3.648657030464007, + "heading": 1.2032167278614567e-18, + "velocityX": -0.004034607939290763, + "velocityY": 2.779074136197618, + "angularVelocity": -3.587245465070565e-18 + }, + { + "timestamp": 1.441791774211821, + "x": 9.442076892829686, + "y": 3.76163527917735, + "heading": 1.0408717529122375e-18, + "velocityX": -0.001525565085163529, + "velocityY": 2.6642269188642267, + "angularVelocity": -3.828383542319785e-18 + }, + { + "timestamp": 1.4841974146298156, + "x": 9.442118595635634, + "y": 3.8697433569545434, + "heading": 8.899938356909357e-19, + "velocityX": 0.000983425904485768, + "velocityY": 2.549379674767898, + "angularVelocity": -3.55797027813502e-18 + }, + { + "timestamp": 1.5266030550478102, + "x": 9.442266692239146, + "y": 3.9729812629833083, + "heading": 7.285255211391333e-19, + "velocityX": 0.0034923798236392647, + "velocityY": 2.434532411516591, + "angularVelocity": -3.8077105384507665e-18 + }, + { + "timestamp": 1.569008695465805, + "x": 9.442521181460629, + "y": 4.071348996653543, + "heading": 5.568860923837275e-19, + "velocityX": 0.006001305925577423, + "velocityY": 2.319685133878004, + "angularVelocity": -4.047563375041425e-18 + }, + { + "timestamp": 1.6114143358837996, + "x": 9.442882062382234, + "y": 4.164846557490197, + "heading": 3.89214419951117e-19, + "velocityX": 0.008510210382726976, + "velocityY": 2.204837845036861, + "angularVelocity": -3.95399672781954e-18 + }, + { + "timestamp": 1.6538199763017942, + "x": 9.443349334269415, + "y": 4.253473945112896, + "heading": 2.1145958274049998e-19, + "velocityX": 0.011019097517791274, + "velocityY": 2.0899905472258355, + "angularVelocity": -4.1917755606155634e-18 + }, + { + "timestamp": 1.6962256167197889, + "x": 9.443922996520996, + "y": 4.337231159210205, + "heading": 0, + "velocityX": 0.013527970475770293, + "velocityY": 1.9751432420706365, + "angularVelocity": -4.9865929033974614e-18 + }, + { + "timestamp": 1.7140312213529185, + "x": 9.444851439716329, + "y": 4.371885132633888, + "heading": -6.384086665630808e-20, + "velocityX": 0.05214331186518852, + "velocityY": 1.946239632840007, + "angularVelocity": -3.585437355003227e-18 + }, + { + "timestamp": 1.7318368259860482, + "x": 9.446439474657646, + "y": 4.405989059480052, + "heading": -1.2895806679414802e-19, + "velocityX": 0.08918736398104961, + "velocityY": 1.9153478665197825, + "angularVelocity": -3.657118908476392e-18 + }, + { + "timestamp": 1.7496424306191778, + "x": 9.448654037918123, + "y": 4.439505555725891, + "heading": -1.9535739456212597e-19, + "velocityX": 0.12437450488808559, + "velocityY": 1.8823565352828266, + "angularVelocity": -3.7291258719060736e-18 + }, + { + "timestamp": 1.7674480352523074, + "x": 9.451456170424079, + "y": 4.472395653726791, + "heading": -2.630514551197965e-19, + "velocityX": 0.1573736227268157, + "velocityY": 1.8471766996162327, + "angularVelocity": -3.8018407655954725e-18 + }, + { + "timestamp": 1.785253639885437, + "x": 9.454800219765596, + "y": 4.5046194646593865, + "heading": -3.3204054645526424e-19, + "velocityX": 0.18780880573410802, + "velocityY": 1.809756624194348, + "angularVelocity": -3.874572393877372e-18 + }, + { + "timestamp": 1.8030592445185667, + "x": 9.45863315790976, + "y": 4.5361371594617745, + "heading": -4.0232225320104645e-19, + "velocityX": 0.21526582349437903, + "velocityY": 1.770099665345931, + "angularVelocity": -3.947168368442765e-18 + }, + { + "timestamp": 1.8208648491516963, + "x": 9.462894162503119, + "y": 4.566910293113452, + "heading": -4.738817957811649e-19, + "velocityX": 0.2393069306635331, + "velocityY": 1.7282835537310302, + "angularVelocity": -4.018934288722903e-18 + }, + { + "timestamp": 1.838670453784826, + "x": 9.467514642286881, + "y": 4.596903433349225, + "heading": -5.466979372881272e-19, + "velocityX": 0.2594958092671896, + "velocityY": 1.6844774919894794, + "angularVelocity": -4.0895074983092414e-18 + }, + { + "timestamp": 1.8564760584179556, + "x": 9.472418880413178, + "y": 4.626085960665692, + "heading": -6.207409559673841e-19, + "velocityX": 0.2754322713184185, + "velocityY": 1.6389517748903728, + "angularVelocity": -4.1584114719162204e-18 + }, + { + "timestamp": 1.8742816630510852, + "x": 9.477525397270549, + "y": 4.654433805173152, + "heading": -6.959741396849906e-19, + "velocityX": 0.2867926679598693, + "velocityY": 1.5920742424390129, + "angularVelocity": -4.225253612980791e-18 + }, + { + "timestamp": 1.8920872676842149, + "x": 9.482748991935516, + "y": 4.681930823696735, + "heading": -7.723538759753341e-19, + "velocityX": 0.2933680025249804, + "velocityY": 1.5442900755202997, + "angularVelocity": -4.2896463843917775e-18 + }, + { + "timestamp": 1.9098928723173445, + "x": 9.488003245817486, + "y": 4.708569546182436, + "heading": -8.498326848116759e-19, + "velocityX": 0.2950898882814487, + "velocityY": 1.4960863747436854, + "angularVelocity": -4.351372577780205e-18 + }, + { + "timestamp": 1.9276984769504741, + "x": 9.493203137170577, + "y": 4.734351147430229, + "heading": -9.283590304652731e-19, + "velocityX": 0.2920367749499054, + "velocityY": 1.4479486531909405, + "angularVelocity": -4.410204415310111e-18 + }, + { + "timestamp": 1.9455040815836038, + "x": 9.498267388376567, + "y": 4.759284683886495, + "heading": -1.0078785533899687e-18, + "velocityX": 0.2844189405716801, + "velocityY": 1.4003195606102483, + "angularVelocity": -4.465981307522584e-18 + }, + { + "timestamp": 1.9633096862167334, + "x": 9.503120261158855, + "y": 4.783385795359616, + "heading": -1.0883359474256107e-18, + "velocityX": 0.27254748615844004, + "velocityY": 1.3535688323818684, + "angularVelocity": -4.518654087152181e-18 + }, + { + "timestamp": 1.981115290849863, + "x": 9.507692676393317, + "y": 4.806675145899408, + "heading": -1.1311853620839733e-18, + "velocityX": 0.25679640364232453, + "velocityY": 1.3079786404139804, + "angularVelocity": -2.406511942248596e-18 + }, + { + "timestamp": 1.9989208954829927, + "x": 9.511922690166164, + "y": 4.829176858482163, + "heading": -1.1748571361283305e-18, + "velocityX": 0.23756642136020728, + "velocityY": 1.263743245252432, + "angularVelocity": -2.4526977117660686e-18 + }, + { + "timestamp": 2.016726500116122, + "x": 9.515755456205326, + "y": 4.850917120727883, + "heading": -1.2662243537310274e-18, + "velocityX": 0.21525615771746257, + "velocityY": 1.2209786016065654, + "angularVelocity": -5.131373562747908e-18 + }, + { + "timestamp": 2.0345321047492515, + "x": 9.519142838088333, + "y": 4.871923049672868, + "heading": -1.3583021162082306e-18, + "velocityX": 0.1902424519021115, + "velocityY": 1.1797369074398463, + "angularVelocity": -5.171279224311694e-18 + }, + { + "timestamp": 2.052337709382381, + "x": 9.522042821424499, + "y": 4.89222183283118, + "heading": -1.4510355551800577e-18, + "velocityX": 0.16286913002499506, + "velocityY": 1.1400221209305184, + "angularVelocity": -5.208102989905589e-18 + }, + { + "timestamp": 2.0701433140155103, + "x": 9.524418841431352, + "y": 4.911840119848378, + "heading": -1.4974409061102444e-18, + "velocityX": 0.133442253481921, + "velocityY": 1.1018040342587163, + "angularVelocity": -2.6062213787679026e-18 + }, + { + "timestamp": 2.0879489186486397, + "x": 9.526239103410534, + "y": 4.930803620151, + "heading": -1.4974658953514371e-18, + "velocityX": 0.10222972017435777, + "velocityY": 1.0650298427573541, + "angularVelocity": -1.4032278309499374e-21 + }, + { + "timestamp": 2.105754523281769, + "x": 9.527475941909024, + "y": 4.949136858822179, + "heading": -1.4979953825818616e-18, + "velocityX": 0.06946343715785236, + "velocityY": 1.029633031223677, + "angularVelocity": -2.973686380366138e-20 + }, + { + "timestamp": 2.1235601279148986, + "x": 9.52810524148387, + "y": 4.966863047915789, + "heading": -1.4520529247658228e-18, + "velocityX": 0.03534278042273317, + "velocityY": 0.9955398571878791, + "angularVelocity": 2.5802244308587756e-18 + }, + { + "timestamp": 2.141365732548028, + "x": 9.528105927185328, + "y": 4.9840040384280595, + "heading": -1.4065278576583552e-18, + "velocityX": 0.00003851042804685489, + "velocityY": 0.9626738808059755, + "angularVelocity": 2.5567829210090895e-18 + }, + { + "timestamp": 2.1591713371811574, + "x": 9.527459524177115, + "y": 5.000580326339002, + "heading": -1.31444940198482e-18, + "velocityX": -0.036303345016051765, + "velocityY": 0.9309590015326615, + "angularVelocity": 5.1713182538767925e-18 + }, + { + "timestamp": 2.176976941814287, + "x": 9.526149781356017, + "y": 5.016611093250944, + "heading": -1.269642784580628e-18, + "velocityX": -0.07355789640877802, + "velocityY": 0.9003214011680397, + "angularVelocity": 2.516432963598342e-18 + }, + { + "timestamp": 2.194782546447416, + "x": 9.524162351863495, + "y": 5.032114267818632, + "heading": -1.2720728525708661e-18, + "velocityX": -0.111618197386393, + "velocityY": 0.8706907115551589, + "angularVelocity": -1.3647769751105282e-19 + }, + { + "timestamp": 2.2125881510805456, + "x": 9.521484522913049, + "y": 5.047106598446598, + "heading": -1.2278446861838926e-18, + "velocityX": -0.1503924750450378, + "velocityY": 0.8420006473732871, + "angularVelocity": 2.4839463646673614e-18 + }, + { + "timestamp": 2.230393755713675, + "x": 9.518104987688332, + "y": 5.061603730851322, + "heading": -1.183859233402495e-18, + "velocityX": -0.18980176715983477, + "velocityY": 0.8141892793548637, + "angularVelocity": 2.4703150854190343e-18 + }, + { + "timestamp": 2.2481993603468045, + "x": 9.514013652772206, + "y": 5.07562028630483, + "heading": -1.1400886719074168e-18, + "velocityX": -0.22977792669371902, + "velocityY": 0.7871990725566343, + "angularVelocity": 2.458246366413904e-18 + }, + { + "timestamp": 2.266004964979934, + "x": 9.50920147540166, + "y": 5.089169937922843, + "heading": -1.0848232169429015e-18, + "velocityX": -0.2702619467128905, + "velocityY": 0.760976776537162, + "angularVelocity": 3.1038235596053945e-18 + }, + { + "timestamp": 2.2838105696130633, + "x": 9.503660325676538, + "y": 5.102265483420015, + "heading": -1.0251358554564357e-18, + "velocityX": -0.3112025589299214, + "velocityY": 0.7354732269416935, + "angularVelocity": 3.352167585142378e-18 + }, + { + "timestamp": 2.3016161742461927, + "x": 9.497382869616938, + "y": 5.114918913468731, + "heading": -9.655885210540119e-19, + "velocityX": -0.35255506279877724, + "velocityY": 0.7106430985878675, + "angularVelocity": 3.3443033960048003e-18 + }, + { + "timestamp": 2.319421778879322, + "x": 9.490362469639482, + "y": 5.127141475270189, + "heading": -8.59228497341353e-19, + "velocityX": -0.3942803472338164, + "velocityY": 0.6864446365791875, + "angularVelocity": 5.9734019707136975e-18 + }, + { + "timestamp": 2.3372273835124515, + "x": 9.48259309960139, + "y": 5.138943731252082, + "heading": -7.529669309175775e-19, + "velocityX": -0.43634407245233126, + "velocityY": 0.6628393826029343, + "angularVelocity": 5.967872426907207e-18 + }, + { + "timestamp": 2.355032988145581, + "x": 9.47406927204869, + "y": 5.150335612998557, + "heading": -5.998533026801316e-19, + "velocityX": -0.47871598456387426, + "velocityY": 0.6397919071661478, + "angularVelocity": 8.599181871609305e-18 + }, + { + "timestamp": 2.3728385927787103, + "x": 9.464785975711115, + "y": 5.161326470632612, + "heading": -3.998698353554635e-19, + "velocityX": -0.5213693400956316, + "velocityY": 0.6172695541946409, + "angularVelocity": 1.1231490104233921e-17 + }, + { + "timestamp": 2.3906441974118398, + "x": 9.454738621622305, + "y": 5.171925117933987, + "heading": -1.9993072194663066e-19, + "velocityX": -0.5642804215768302, + "velocityY": 0.5952422015289273, + "angularVelocity": 1.1228999117764367e-17 + }, + { + "timestamp": 2.408449802044969, + "x": 9.443922996520996, + "y": 5.182139873504639, + "heading": 0, + "velocityX": -0.6074281286234412, + "velocityY": 0.5736820389490421, + "angularVelocity": 1.1228527488456345e-17 + }, + { + "timestamp": 2.441083473597997, + "x": 9.421235266185908, + "y": 5.201198581045461, + "heading": 3.6632091737902714e-19, + "velocityX": -0.695224571903227, + "velocityY": 0.584019714418288, + "angularVelocity": 1.1225243708183917e-17 + }, + { + "timestamp": 2.473717145151025, + "x": 9.395678476358919, + "y": 5.220559316480926, + "heading": 3.950269546669323e-19, + "velocityX": -0.7831417248119713, + "velocityY": 0.5932748144505112, + "angularVelocity": 8.796442845638519e-19 + }, + { + "timestamp": 2.506350816704053, + "x": 9.367248792322409, + "y": 5.2401831140518045, + "heading": 4.225934108245564e-19, + "velocityX": -0.8711763857251311, + "velocityY": 0.6013358790778222, + "angularVelocity": 8.447238066106848e-19 + }, + { + "timestamp": 2.538984488257081, + "x": 9.33594258785004, + "y": 5.260026803817625, + "heading": 3.959837725893085e-19, + "velocityX": -0.9593221658033272, + "velocityY": 0.6080740787493973, + "angularVelocity": -8.154050996492256e-19 + }, + { + "timestamp": 2.571618159810109, + "x": 9.301756592559922, + "y": 5.28004232712052, + "heading": 3.114803772539543e-19, + "velocityX": -1.0475681608354517, + "velocityY": 0.6133396075390749, + "angularVelocity": -2.5894552382449347e-18 + }, + { + "timestamp": 2.604251831363137, + "x": 9.264688101016896, + "y": 5.300175904395579, + "heading": 1.947640695222268e-19, + "velocityX": -1.135897059048004, + "velocityY": 0.6169571585698372, + "angularVelocity": -3.576562153024813e-18 + }, + { + "timestamp": 2.636885502916165, + "x": 9.224735270640254, + "y": 5.320367016783676, + "heading": 7.40663093278534e-20, + "velocityX": -1.2242824198226732, + "velocityY": 0.6187202183268213, + "angularVelocity": -3.6985649278098886e-18 + }, + { + "timestamp": 2.669519174469193, + "x": 9.181897548648003, + "y": 5.3405471520145635, + "heading": -4.738766542721829e-20, + "velocityX": -1.312684719604387, + "velocityY": 0.6183838431448163, + "angularVelocity": -3.721737827523668e-18 + }, + { + "timestamp": 2.702152846022221, + "x": 9.136176288552582, + "y": 5.360638251356262, + "heading": -1.3919438561122211e-19, + "velocityX": -1.4010455434388964, + "velocityY": 0.6156554989239036, + "angularVelocity": -2.8132510835047748e-18 + }, + { + "timestamp": 2.734786517575249, + "x": 9.087575648237515, + "y": 5.38055077835316, + "heading": -3.1451627198444227e-19, + "velocityX": -1.4892789564328437, + "velocityY": 0.6101834715269836, + "angularVelocity": -5.37242301252158e-18 + }, + { + "timestamp": 2.767420189128277, + "x": 9.036103910894113, + "y": 5.400181313477486, + "heading": -4.984458978394373e-19, + "velocityX": -1.577258545970237, + "velocityY": 0.6015423392500471, + "angularVelocity": -5.636191538862516e-18 + }, + { + "timestamp": 2.800053860681305, + "x": 8.981775447032602, + "y": 5.4194095675394145, + "heading": -6.925837136135975e-19, + "velocityX": -1.6647977771434062, + "velocityY": 0.5892151617290188, + "angularVelocity": -5.949003213880137e-18 + }, + { + "timestamp": 2.832687532234333, + "x": 8.924613654513877, + "y": 5.438094715812673, + "heading": -8.987704525662525e-19, + "velocityX": -1.7516200230745813, + "velocityY": 0.5725726644915266, + "angularVelocity": -6.318220846486254e-18 + }, + { + "timestamp": 2.865321203787361, + "x": 8.864655390388519, + "y": 5.456071019769574, + "heading": -1.0294610256530182e-18, + "velocityX": -1.8373128511735881, + "velocityY": 0.5508514090329182, + "angularVelocity": -4.004776778391296e-18 + }, + { + "timestamp": 2.897954875340389, + "x": 8.801957649624493, + "y": 5.4731429013815855, + "heading": -1.1767280866403955e-18, + "velocityX": -1.9212591712870637, + "velocityY": 0.5231370176742964, + "angularVelocity": -4.512733482684496e-18 + }, + { + "timestamp": 2.930588546893417, + "x": 8.736607504769767, + "y": 5.489080118872384, + "heading": -1.1856206374138729e-18, + "velocityX": -2.0025373102298354, + "velocityY": 0.48836728239122423, + "angularVelocity": -2.7249636003536904e-19 + }, + { + "timestamp": 2.963222218446445, + "x": 8.668736377664992, + "y": 5.503614711495437, + "heading": -1.2166901874810268e-18, + "velocityX": -2.079788263925095, + "velocityY": 0.445386373379314, + "angularVelocity": -9.520702152066405e-19 + }, + { + "timestamp": 2.995855889999473, + "x": 8.598538931192524, + "y": 5.51644315523542, + "heading": -1.272875294996435e-18, + "velocityX": -2.1510741247243037, + "velocityY": 0.3931045184156154, + "angularVelocity": -1.721691325591454e-18 + }, + { + "timestamp": 3.028489561552501, + "x": 8.526293982060697, + "y": 5.5272392514284645, + "heading": -1.3568263007892658e-18, + "velocityX": -2.2138161504271343, + "velocityY": 0.3308268937960027, + "angularVelocity": -2.5725269220569475e-18 + }, + { + "timestamp": 3.061123233105529, + "x": 8.452378864421089, + "y": 5.5356830638050605, + "heading": -1.1202008395033444e-18, + "velocityX": -2.264995451691677, + "velocityY": 0.2587453992995388, + "angularVelocity": 7.250961237685142e-18 + }, + { + "timestamp": 3.093756904658557, + "x": 8.377262861304947, + "y": 5.541503791129315, + "heading": -7.567982278279353e-19, + "velocityX": -2.3017944209582493, + "velocityY": 0.1783656894014662, + "angularVelocity": 1.1135818174546654e-17 + }, + { + "timestamp": 3.126390576211585, + "x": 8.301470281296071, + "y": 5.544520067523571, + "heading": -4.2451642109200585e-19, + "velocityX": -2.322526899424121, + "velocityY": 0.09242834933104346, + "angularVelocity": 1.0182177094305531e-17 + }, + { + "timestamp": 3.159024247764613, + "x": 8.225524229056585, + "y": 5.5446555195936496, + "heading": -6.419282428655621e-20, + "velocityX": -2.327229779097387, + "velocityY": 0.004150684358640343, + "angularVelocity": 1.104146740013862e-17 + }, + { + "timestamp": 3.191657919317641, + "x": 8.149897657636762, + "y": 5.541923806442718, + "heading": 2.6600608408756135e-19, + "velocityX": -2.3174398656595123, + "velocityY": -0.08370842203557924, + "angularVelocity": 1.0118350537396719e-17 + }, + { + "timestamp": 3.224291590870669, + "x": 8.074988972359481, + "y": 5.536397930435266, + "heading": 5.669464384757661e-19, + "velocityX": -2.295441539747066, + "velocityY": -0.16933050265189162, + "angularVelocity": 9.221774814473882e-18 + }, + { + "timestamp": 3.256925262423697, + "x": 8.001120065278322, + "y": 5.528181037877018, + "heading": 8.396159802906952e-19, + "velocityX": -2.263579412482889, + "velocityY": -0.251791850785044, + "angularVelocity": 8.355466655505314e-18 + }, + { + "timestamp": 3.289558933976725, + "x": 7.928546140625048, + "y": 5.517386213720495, + "heading": 1.0850578237345321e-18, + "velocityX": -2.2238970118746137, + "velocityY": -0.33078791453121625, + "angularVelocity": 7.521122855720812e-18 + }, + { + "timestamp": 3.322192605529753, + "x": 7.857468753455215, + "y": 5.504124997826886, + "heading": 1.2498038775969776e-18, + "velocityX": -2.1780383201546814, + "velocityY": -0.40636604042728, + "angularVelocity": 5.048345584833791e-18 + }, + { + "timestamp": 3.354826277082781, + "x": 7.788047870036826, + "y": 5.488501852729208, + "heading": 1.3893738984859056e-18, + "velocityX": -2.1272777506994864, + "velocityY": -0.47874310042900636, + "angularVelocity": 4.276871388382114e-18 + }, + { + "timestamp": 3.387459948635809, + "x": 7.720411653283996, + "y": 5.470612062415975, + "heading": 1.0686978502777718e-18, + "velocityX": -2.0725898599220134, + "velocityY": -0.5482003544763124, + "angularVelocity": -9.826540893112917e-18 + }, + { + "timestamp": 3.420093620188837, + "x": 7.654663966143918, + "y": 5.450541406963203, + "heading": 7.246751826948704e-19, + "velocityX": -2.014719276476262, + "velocityY": -0.6150290328245204, + "angularVelocity": -1.0541955993846661e-17 + }, + { + "timestamp": 3.4527272917418648, + "x": 7.590889993639064, + "y": 5.4283666677544415, + "heading": 6.49705937648609e-19, + "velocityX": -1.954238351673864, + "velocityY": -0.6795048841724649, + "angularVelocity": -2.2972967003537705e-18 + }, + { + "timestamp": 3.4853609632948928, + "x": 7.529160428726087, + "y": 5.40415646387206, + "heading": 5.529406335391227e-19, + "velocityX": -1.8915911687310976, + "velocityY": -0.7418780275165117, + "angularVelocity": -2.9651976681071948e-18 + }, + { + "timestamp": 3.5179946348479207, + "x": 7.4695345966300986, + "y": 5.377972170861107, + "heading": 4.350554097070228e-19, + "velocityX": -1.827126071275839, + "velocityY": -0.8023704279919941, + "angularVelocity": -3.612379562157046e-18 + }, + { + "timestamp": 3.5506283064009487, + "x": 7.412062803528599, + "y": 5.349868806100156, + "heading": 2.9666664077545544e-19, + "velocityX": -1.76111943175355, + "velocityY": -0.8611769201416861, + "angularVelocity": -4.24067376305906e-18 + }, + { + "timestamp": 3.5832619779539767, + "x": 7.3567881189273505, + "y": 5.31989583302525, + "heading": 1.3833796557360445e-19, + "velocityX": -1.6937930049161405, + "velocityY": -0.9184676945161352, + "angularVelocity": -4.851696264215519e-18 + }, + { + "timestamp": 3.6158956495070047, + "x": 7.303747742547076, + "y": 5.288097869990755, + "heading": -3.941532186257001e-20, + "velocityX": -1.6253266597381706, + "velocityY": -0.9743912199038477, + "angularVelocity": -5.446928506404398e-18 + }, + { + "timestamp": 3.6485293210600327, + "x": 7.252974063954799, + "y": 5.254515305256301, + "heading": -7.88746893068946e-21, + "velocityX": -1.5558677947031856, + "velocityY": -1.029077119927617, + "angularVelocity": 9.661145052202089e-19 + }, + { + "timestamp": 3.6811629926130607, + "x": 7.2044954928258065, + "y": 5.219184826255724, + "heading": 5.118481093167075e-21, + "velocityX": -1.4855383664145283, + "velocityY": -1.082638799718508, + "angularVelocity": 3.9854416876380984e-19 + }, + { + "timestamp": 3.7137966641660887, + "x": 7.158337116241455, + "y": 5.182139873504639, + "heading": 0, + "velocityX": -1.4144401897698629, + "velocityY": -1.1351757552284538, + "angularVelocity": -1.5684683960049997e-19 + }, + { + "timestamp": 3.7414907274933724, + "x": 7.120852532109941, + "y": 5.149489538414079, + "heading": 1.0745519784573005e-20, + "velocityX": -1.353524171896549, + "velocityY": -1.178965134321498, + "angularVelocity": 3.8800874694948773e-19 + }, + { + "timestamp": 3.769184790820656, + "x": 7.08508589038847, + "y": 5.115670726143776, + "heading": 9.195270075585857e-21, + "velocityX": -1.2914912954009872, + "velocityY": -1.221157468683352, + "angularVelocity": -5.597697879888322e-20 + }, + { + "timestamp": 3.79687885414794, + "x": 7.0510680175463785, + "y": 5.080730097325854, + "heading": -4.120447004048063e-21, + "velocityX": -1.228345311414701, + "velocityY": -1.2616649425907351, + "angularVelocity": -4.808141205686055e-19 + }, + { + "timestamp": 3.8245729174752237, + "x": 7.018829493833099, + "y": 5.044716816861446, + "heading": -2.8635234930444935e-20, + "velocityX": -1.1640951106484203, + "velocityY": -1.3003971298399937, + "angularVelocity": -8.851987690468531e-19 + }, + { + "timestamp": 3.8522669808025074, + "x": 6.988400495078303, + "y": 5.007682613177794, + "heading": -6.374294844247492e-20, + "velocityX": -1.098755296223239, + "velocityY": -1.3372614645235503, + "angularVelocity": -1.2676968124680518e-18 + }, + { + "timestamp": 3.879961044129791, + "x": 6.959810618911943, + "y": 4.969681821257425, + "heading": -1.0372073464335989e-19, + "velocityX": -1.0323467462498963, + "velocityY": -1.3721638270007799, + "angularVelocity": -1.4435495083754531e-18 + }, + { + "timestamp": 3.907655107457075, + "x": 6.933088696208582, + "y": 4.930771406065292, + "heading": -1.5295745974019348e-19, + "velocityX": -0.9648971473620426, + "velocityY": -1.4050092517047952, + "angularVelocity": -1.777878869589048e-18 + }, + { + "timestamp": 3.9353491707843586, + "x": 6.908262589169743, + "y": 4.891010962916479, + "heading": -2.1072283099568796e-19, + "velocityX": -0.8964414772020872, + "velocityY": -1.4357027597911687, + "angularVelocity": -2.0858393494447477e-18 + }, + { + "timestamp": 3.9630432341116424, + "x": 6.885358978142829, + "y": 4.850462691377148, + "heading": -2.7624488082850763e-19, + "velocityX": -0.827022411129839, + "velocityY": -1.4641503148215067, + "angularVelocity": -2.3659238652212594e-18 + }, + { + "timestamp": 3.990737297438926, + "x": 6.864403140012061, + "y": 4.809191339506532, + "heading": -2.4182243014725925e-19, + "velocityX": -0.7566906265474782, + "velocityY": -1.4902598937135898, + "angularVelocity": 1.2429539162791189e-18 + }, + { + "timestamp": 4.01843136076621, + "x": 6.845418721750748, + "y": 4.767264115655309, + "heading": -2.13489838207875e-19, + "velocityX": -0.685504977617706, + "velocityY": -1.5139426582417082, + "angularVelocity": 1.0230562964475242e-18 + }, + { + "timestamp": 4.0461254240934945, + "x": 6.828427513449241, + "y": 4.7247505656541895, + "heading": -1.9035484353323274e-19, + "velocityX": -0.6135325141964989, + "velocityY": -1.5351142047557378, + "angularVelocity": 8.353771837793482e-19 + }, + { + "timestamp": 4.073819487420779, + "x": 6.813449225773627, + "y": 4.681722414060745, + "heading": -1.7149141991215955e-19, + "velocityX": -0.5408483218444247, + "velocityY": -1.5536958619955332, + "angularVelocity": 6.811357830936083e-19 + }, + { + "timestamp": 4.101513550748063, + "x": 6.8005012773057025, + "y": 4.638253369169532, + "heading": -1.5593935716162944e-19, + "velocityX": -0.4675351650246373, + "velocityY": -1.569615999555684, + "angularVelocity": 5.615664370799311e-19 + }, + { + "timestamp": 4.129207614075347, + "x": 6.789598597504067, + "y": 4.594418892696229, + "heading": -1.427091986664009e-19, + "velocityX": -0.3936829230434275, + "velocityY": -1.5828113034650333, + "angularVelocity": 4.777252028217134e-19 + }, + { + "timestamp": 4.156901677402631, + "x": 6.7807534510551255, + "y": 4.550295936364767, + "heading": -1.3078707268298111e-19, + "velocityX": -0.3193878176853724, + "velocityY": -1.5932279712811777, + "angularVelocity": 4.304936779834702e-19 + }, + { + "timestamp": 4.1845957407299155, + "x": 6.773975289112579, + "y": 4.50596264898097, + "heading": -1.1914143965999851e-19, + "velocityX": -0.2447514423016853, + "velocityY": -1.6008227777871797, + "angularVelocity": 4.205098273160101e-19 + }, + { + "timestamp": 4.2122898040572, + "x": 6.769270632337623, + "y": 4.461498058876275, + "heading": -8.246208709796346e-20, + "velocityX": -0.16987961352428851, + "velocityY": -1.6055639643493063, + "angularVelocity": 1.3244478396697712e-18 + }, + { + "timestamp": 4.239983867384484, + "x": 6.766642989760458, + "y": 4.416981737753159, + "heading": -6.835343094343368e-20, + "velocityX": -0.09488107780040866, + "velocityY": -1.6074319104794648, + "angularVelocity": 5.094467867757219e-19 + }, + { + "timestamp": 4.267677930711768, + "x": 6.766092816327569, + "y": 4.372493452867139, + "heading": -4.5283135279092575e-20, + "velocityX": -0.019866114494882854, + "velocityY": -1.6064195549877718, + "angularVelocity": 8.330410070957423e-19 + }, + { + "timestamp": 4.295371994039052, + "x": 6.767617510647199, + "y": 4.328112815061299, + "heading": -1.83116755901566e-20, + "velocityX": 0.05505491561896332, + "velocityY": -1.6025325457429587, + "angularVelocity": 9.739074640031068e-19 + }, + { + "timestamp": 4.323066057366336, + "x": 6.771211452987862, + "y": 4.28391893037677, + "heading": -3.461364002947858e-20, + "velocityX": 0.1297730238496046, + "velocityY": -1.5957891105488256, + "angularVelocity": -5.886446259595525e-19 + }, + { + "timestamp": 4.350760120693621, + "x": 6.776866082124187, + "y": 4.239990062777867, + "heading": -4.498980952085583e-20, + "velocityX": 0.20418199631809572, + "velocityY": -1.586219655807003, + "angularVelocity": -3.74671184772026e-19 + }, + { + "timestamp": 4.378454184020905, + "x": 6.784570008263401, + "y": 4.196403314970527, + "heading": -8.839742873815279e-20, + "velocityX": 0.2781796967880941, + "velocityY": -1.573866113189625, + "angularVelocity": -1.567397663024212e-18 + }, + { + "timestamp": 4.406148247348189, + "x": 6.794309158115849, + "y": 4.153234333407163, + "heading": -1.8339666089580011e-19, + "velocityX": 0.35166922734851225, + "velocityY": -1.558781066295692, + "angularVelocity": -3.4303098461228627e-18 + }, + { + "timestamp": 4.433842310675473, + "x": 6.806066947263768, + "y": 4.110557042436363, + "heading": -2.696427100318041e-19, + "velocityX": 0.42455991412196786, + "velocityY": -1.5410266982654612, + "angularVelocity": -3.114242761138099e-18 + }, + { + "timestamp": 4.461536374002757, + "x": 6.819824474376613, + "y": 4.068443411264147, + "heading": -3.4626467085586136e-19, + "velocityX": 0.49676809611723804, + "velocityY": -1.520673606993746, + "angularVelocity": -2.7667283142663646e-18 + }, + { + "timestamp": 4.489230437330042, + "x": 6.83556073153069, + "y": 4.026963256042092, + "heading": -4.1243476277543403e-19, + "velocityX": 0.5682177067376644, + "velocityY": -1.4977995367400567, + "angularVelocity": -2.3893236872795488e-18 + }, + { + "timestamp": 4.516924500657326, + "x": 6.8532528249006415, + "y": 3.986184078077806, + "heading": -4.673685141873994e-19, + "velocityX": 0.6388406482959381, + "velocityY": -1.4724880737926662, + "angularVelocity": -1.9835931108962957e-18 + }, + { + "timestamp": 4.54461856398461, + "x": 6.8728762003622395, + "y": 3.9461709379519925, + "heading": -5.103268481000934e-19, + "velocityX": 0.7085769693559092, + "velocityY": -1.4448273499249418, + "angularVelocity": -1.5511753625583402e-18 + }, + { + "timestamp": 4.572312627311894, + "x": 6.8944048690270705, + "y": 3.9069863642805704, + "heading": -5.406144797086824e-19, + "velocityX": 0.7773748622731119, + "velocityY": -1.4149087914021297, + "angularVelocity": -1.0936517020884735e-18 + }, + { + "timestamp": 4.600006690639178, + "x": 6.917811628359295, + "y": 3.8686902950155, + "heading": -4.440474823091974e-19, + "velocityX": 0.8451905036688525, + "velocityY": -1.3828259440477353, + "angularVelocity": 3.486919029620622e-18 + }, + { + "timestamp": 4.6277007539664625, + "x": 6.943068275241948, + "y": 3.831340048547767, + "heading": -3.335518357804389e-19, + "velocityX": 0.911987763737461, + "velocityY": -1.3486733971224423, + "angularVelocity": 3.9898665024985945e-18 + }, + { + "timestamp": 4.655394817293747, + "x": 6.970145808109622, + "y": 3.7949903214566754, + "heading": -2.0856300853582498e-19, + "velocityX": 0.9777378114463198, + "velocityY": -1.3125458211572592, + "angularVelocity": 4.513198126042523e-18 + }, + { + "timestamp": 4.683088880621031, + "x": 6.9990146159995055, + "y": 3.7596932095232787, + "heading": -1.8209221598354913e-19, + "velocityX": 1.0424186421730879, + "velocityY": -1.2745371279129505, + "angularVelocity": 9.558283193675835e-19 + }, + { + "timestamp": 4.710782943948315, + "x": 7.029644653058208, + "y": 3.725498248565643, + "heading": -2.1000804685949047e-19, + "velocityX": 1.1060145525313745, + "velocityY": -1.2347397546370906, + "angularVelocity": -1.0080081201848759e-18 + }, + { + "timestamp": 4.738477007275599, + "x": 7.062005597653486, + "y": 3.692452471728192, + "heading": -1.084446977273025e-19, + "velocityX": 1.168515584471714, + "velocityY": -1.193244069926507, + "angularVelocity": 3.667332467594088e-18 + }, + { + "timestamp": 4.7661710706028835, + "x": 7.096066995764078, + "y": 3.6606004800341547, + "heading": -1.3461920373400012e-20, + "velocityX": 1.2299169575825302, + "velocityY": -1.1501378948121377, + "angularVelocity": 3.429715902110701e-18 + }, + { + "timestamp": 4.793865133930168, + "x": 7.131798388752283, + "y": 3.629984523258401, + "heading": -1.5274380466475932e-20, + "velocityX": 1.2902185051697632, + "velocityY": -1.105506130102267, + "angularVelocity": -6.54457296822698e-20 + }, + { + "timestamp": 4.821559197257452, + "x": 7.1691694259643555, + "y": 3.600644588470459, + "heading": 0, + "velocityX": 1.3494241264067142, + "velocityY": -1.0594304794210403, + "angularVelocity": 5.515398649571509e-19 + }, + { + "timestamp": 4.860229979851676, + "x": 7.224490933942949, + "y": 3.562237323488572, + "heading": -1.4273741900724991e-19, + "velocityX": 1.4305763749103853, + "velocityY": -0.9931856147028838, + "angularVelocity": -3.691092303190871e-18 + }, + { + "timestamp": 4.8989007624459, + "x": 7.2829218829627, + "y": 3.526426656699073, + "heading": -2.826990069245146e-20, + "velocityX": 1.5109843944166248, + "velocityY": -0.92603936065278, + "angularVelocity": 2.9600508098266124e-18 + }, + { + "timestamp": 4.937571545040123, + "x": 7.344429149979499, + "y": 3.493251746439967, + "heading": 1.2416945578820799e-19, + "velocityX": 1.5905358746472524, + "velocityY": -0.8578804987530882, + "angularVelocity": 3.941977094311565e-18 + }, + { + "timestamp": 4.976242327634347, + "x": 7.408974239733027, + "y": 3.4627568691940223, + "heading": 5.383607057807366e-19, + "velocityX": 1.6690918937639638, + "velocityY": -0.7885766772793149, + "angularVelocity": 1.0710701988609312e-17 + }, + { + "timestamp": 5.014913110228571, + "x": 7.476511914328953, + "y": 3.434992445897612, + "heading": 7.743218382860568e-19, + "velocityX": 1.7464780918608307, + "velocityY": -0.7179690048619871, + "angularVelocity": 6.101793487036617e-18 + }, + { + "timestamp": 5.053583892822795, + "x": 7.5469883327111305, + "y": 3.4100163422501466, + "heading": 1.0565848104622019e-18, + "velocityX": 1.8224719970550483, + "velocityY": -0.6458649650186884, + "angularVelocity": 7.29912787877777e-18 + }, + { + "timestamp": 5.092254675417019, + "x": 7.620338469503448, + "y": 3.3878955288635875, + "heading": 1.7969259306275936e-18, + "velocityX": 1.896784390478618, + "velocityY": -0.57202911093561, + "angularVelocity": 1.9144713618424857e-17 + }, + { + "timestamp": 5.130925458011243, + "x": 7.696482446244184, + "y": 3.368708211087513, + "heading": 2.1772966886455785e-18, + "velocityX": 1.9690311814922792, + "velocityY": -0.49617091997871005, + "angularVelocity": 9.836126791797473e-18 + }, + { + "timestamp": 5.1695962406054665, + "x": 7.7753201738126005, + "y": 3.3525465572778215, + "heading": 2.2655219858710494e-18, + "velocityX": 2.038689736271096, + "velocityY": -0.4179293183506455, + "angularVelocity": 2.2814472891884663e-18 + }, + { + "timestamp": 5.20826702319969, + "x": 7.856723292228703, + "y": 3.3395201391961975, + "heading": 2.1978350166492497e-18, + "velocityX": 2.1050289897225842, + "velocityY": -0.33685426587587375, + "angularVelocity": -1.7503375651963432e-18 + }, + { + "timestamp": 5.246937805793914, + "x": 7.940522653406374, + "y": 3.3297600570672055, + "heading": 2.424348273216306e-18, + "velocityX": 2.166994189307819, + "velocityY": -0.2523890512225693, + "angularVelocity": 5.857478253606304e-18 + }, + { + "timestamp": 5.285608588388138, + "x": 8.026488266632105, + "y": 3.3234231719471747, + "heading": 2.134590026356317e-18, + "velocityX": 2.223011986278472, + "velocityY": -0.16386751689312626, + "angularVelocity": -7.492948496000614e-18 + }, + { + "timestamp": 5.324279370982362, + "x": 8.1142964045733, + "y": 3.320694059402225, + "heading": 1.9377574367066e-18, + "velocityX": 2.270658415749503, + "velocityY": -0.07057298461180006, + "angularVelocity": -5.089954885991328e-18 + }, + { + "timestamp": 5.362950153576586, + "x": 8.203475863616505, + "y": 3.3217768219584887, + "heading": 1.8474257066253063e-18, + "velocityX": 2.306119841922259, + "velocityY": 0.027999499457421157, + "angularVelocity": -2.3359164889328848e-18 + }, + { + "timestamp": 5.40162093617081, + "x": 8.293327802057727, + "y": 3.326854415713941, + "heading": 1.879986343890872e-18, + "velocityX": 2.3235096994038806, + "velocityY": 0.1313031031394509, + "angularVelocity": 8.419990651878979e-19 + }, + { + "timestamp": 5.4402917187650335, + "x": 8.382847452378353, + "y": 3.3359693948238105, + "heading": 1.943872151906946e-18, + "velocityX": 2.314916955779332, + "velocityY": 0.23570712818288259, + "angularVelocity": 1.6520466355085231e-18 + }, + { + "timestamp": 5.478962501359257, + "x": 8.470783550505773, + "y": 3.3488130804859626, + "heading": 2.1687712359482573e-18, + "velocityX": 2.2739673786832317, + "velocityY": 0.3321289304362025, + "angularVelocity": 5.8157392041052145e-18 + }, + { + "timestamp": 5.517633283953481, + "x": 8.555976068741822, + "y": 3.364637313238136, + "heading": 2.2495148531033526e-18, + "velocityX": 2.203020278383855, + "velocityY": 0.4092038404864077, + "angularVelocity": 2.087977525164704e-18 + }, + { + "timestamp": 5.556304066547705, + "x": 8.637675493242655, + "y": 3.382513178337331, + "heading": 2.3065202944378103e-18, + "velocityX": 2.1126912624994216, + "velocityY": 0.46225765034978306, + "angularVelocity": 1.4741219888713533e-18 + }, + { + "timestamp": 5.594974849141929, + "x": 8.715517230799358, + "y": 3.4016256353771546, + "heading": 2.150607115589708e-18, + "velocityX": 2.0129341154924116, + "velocityY": 0.49423507251897597, + "angularVelocity": -4.0318086405284845e-18 + }, + { + "timestamp": 5.633645631736153, + "x": 8.789355423341263, + "y": 3.42135659338803, + "heading": 1.7517953363711107e-18, + "velocityX": 1.909405178496008, + "velocityY": 0.5102290847825096, + "angularVelocity": -1.0312999914821358e-17 + }, + { + "timestamp": 5.672316414330377, + "x": 8.859146004052764, + "y": 3.441254167538288, + "heading": 1.416161918834889e-18, + "velocityX": 1.8047367037750677, + "velocityY": 0.5145376642371936, + "angularVelocity": -8.679250929848945e-18 + }, + { + "timestamp": 5.7109871969246, + "x": 8.924888961953693, + "y": 3.460985377675674, + "heading": 1.2028399924524531e-18, + "velocityX": 1.7000679451144207, + "velocityY": 0.5102356046017003, + "angularVelocity": -5.516359997505784e-18 + }, + { + "timestamp": 5.749657979518824, + "x": 8.986602419973897, + "y": 3.4802993804547686, + "heading": 8.295806023476167e-19, + "velocityX": 1.595867833029694, + "velocityY": 0.4994469075466367, + "angularVelocity": -9.652232660551833e-18 + }, + { + "timestamp": 5.788328762113048, + "x": 9.044311163070581, + "y": 3.499002488214024, + "heading": 3.165440414148323e-19, + "velocityX": 1.4923086429935726, + "velocityY": 0.4836495799815523, + "angularVelocity": -1.3266774338561772e-17 + }, + { + "timestamp": 5.826999544707272, + "x": 9.098041553812648, + "y": 3.516941626488888, + "heading": -1.3634511417910052e-19, + "velocityX": 1.3894311709660454, + "velocityY": 0.46389385141491557, + "angularVelocity": -1.1711403346191615e-17 + }, + { + "timestamp": 5.865670327301496, + "x": 9.147819310254551, + "y": 3.5339932846439632, + "heading": -5.351657410219041e-19, + "velocityX": 1.287218750244256, + "velocityY": 0.44094422225686936, + "angularVelocity": -1.0313228436099753e-17 + }, + { + "timestamp": 5.90434110989572, + "x": 9.193668593077833, + "y": 3.5500559859721394, + "heading": -8.103923290509881e-19, + "velocityX": 1.1856311082292463, + "velocityY": 0.4153704748290859, + "angularVelocity": -7.1171713469746e-18 + }, + { + "timestamp": 5.9430118924899435, + "x": 9.235611699378987, + "y": 3.565045036055544, + "heading": -1.0408712708752226e-18, + "velocityX": 1.0846200538858524, + "velocityY": 0.3876065876578114, + "angularVelocity": -5.960028046884079e-18 + }, + { + "timestamp": 5.981682675084167, + "x": 9.2736690360789, + "y": 3.578888774891126, + "heading": -1.2302348448445404e-18, + "velocityX": 0.9841367085649779, + "velocityY": 0.3579896217991075, + "angularVelocity": -4.896813153460037e-18 + }, + { + "timestamp": 6.020353457678391, + "x": 9.307859217238196, + "y": 3.59152584378987, + "heading": -1.3138022795035935e-18, + "velocityX": 0.8841347101262037, + "velocityY": 0.3267859621912809, + "angularVelocity": -2.160997315257982e-18 + }, + { + "timestamp": 6.059024240272615, + "x": 9.338199210185026, + "y": 3.6029031524068102, + "heading": -1.362101109862026e-18, + "velocityX": 0.7845714751933003, + "velocityY": 0.29420942255871, + "angularVelocity": -1.2489755201874302e-18 + }, + { + "timestamp": 6.097695022866839, + "x": 9.364704494330118, + "y": 3.612974339107483, + "heading": -1.3775148409871813e-18, + "velocityX": 0.6854085272391679, + "velocityY": 0.2604340027547543, + "angularVelocity": -3.9859007505180033e-19 + }, + { + "timestamp": 6.136365805461063, + "x": 9.387389215756244, + "y": 3.621698585836685, + "heading": -9.194127131953696e-19, + "velocityX": 0.5866113873142459, + "velocityY": 0.22560305594913474, + "angularVelocity": 1.184620555949573e-17 + }, + { + "timestamp": 6.175036588055287, + "x": 9.406266330244824, + "y": 3.6290396923599735, + "heading": -4.324037121145138e-19, + "velocityX": 0.48814927503944505, + "velocityY": 0.1898359958297115, + "angularVelocity": 1.2593717368297416e-17 + }, + { + "timestamp": 6.2137073706495105, + "x": 9.421347732169448, + "y": 3.634965343433838, + "heading": -6.350098887170209e-19, + "velocityX": 0.38999474313399257, + "velocityY": 0.1532332856058955, + "angularVelocity": -5.239258436014818e-18 + }, + { + "timestamp": 6.252378153243734, + "x": 9.432644369013142, + "y": 3.639446521662576, + "heading": -4.293741073807372e-19, + "velocityX": 0.2921233056550846, + "velocityY": 0.1158802053674366, + "angularVelocity": 5.317599602073295e-18 + }, + { + "timestamp": 6.291048935837958, + "x": 9.440166342343868, + "y": 3.642457031895519, + "heading": 2.1988295300212938e-20, + "velocityX": 0.19451308781759213, + "velocityY": 0.07784973644138414, + "angularVelocity": 1.1671920640227671e-17 + }, + { + "timestamp": 6.329719718432182, + "x": 9.443922996520996, + "y": 3.6439731121063232, + "heading": 0, + "velocityX": 0.09714450872500752, + "velocityY": 0.03920479775939959, + "angularVelocity": -5.686029032587966e-19 + }, + { + "timestamp": 6.368390501026406, + "x": 9.443922996520996, + "y": 3.6439731121063232, + "heading": 0, + "velocityX": 1.8284117622554373e-32, + "velocityY": 7.799691816180278e-34, + "angularVelocity": 0 + } + ] + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/frc/team449/Main.kt b/src/main/kotlin/frc/team449/Main.kt new file mode 100644 index 0000000..18b6c47 --- /dev/null +++ b/src/main/kotlin/frc/team449/Main.kt @@ -0,0 +1,9 @@ +@file:JvmName("Main") + +package frc.team449 + +import edu.wpi.first.wpilibj.RobotBase + +fun main() { + RobotBase.startRobot { RobotLoop() } +} diff --git a/src/main/kotlin/frc/team449/RobotBase.kt b/src/main/kotlin/frc/team449/RobotBase.kt new file mode 100644 index 0000000..03c5981 --- /dev/null +++ b/src/main/kotlin/frc/team449/RobotBase.kt @@ -0,0 +1,17 @@ +package frc.team449 + +import edu.wpi.first.wpilibj.PowerDistribution +import edu.wpi.first.wpilibj.smartdashboard.Field2d +import edu.wpi.first.wpilibj2.command.Command +import frc.team449.control.holonomic.HolonomicDrive + +abstract class RobotBase { + + val field = Field2d() + + abstract val powerDistribution: PowerDistribution + + abstract val drive: HolonomicDrive? + + abstract val driveCommand: Command +} diff --git a/src/main/kotlin/frc/team449/RobotLoop.kt b/src/main/kotlin/frc/team449/RobotLoop.kt new file mode 100644 index 0000000..d3acdf1 --- /dev/null +++ b/src/main/kotlin/frc/team449/RobotLoop.kt @@ -0,0 +1,139 @@ +package frc.team449 + +import edu.wpi.first.wpilibj.DriverStation +import edu.wpi.first.wpilibj.RobotBase +import edu.wpi.first.wpilibj.TimedRobot +import edu.wpi.first.wpilibj.Timer +import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard +import edu.wpi.first.wpilibj2.command.Command +import edu.wpi.first.wpilibj2.command.CommandScheduler +import edu.wpi.first.wpilibj2.command.InstantCommand +import frc.team449.control.holonomic.SwerveSim +import frc.team449.robot2023.Robot +import frc.team449.robot2023.auto.routines.RoutineChooser +import frc.team449.robot2023.commands.light.BlairChasing +import frc.team449.robot2023.commands.light.BreatheHue +import frc.team449.robot2023.commands.light.Rainbow +import frc.team449.robot2023.constants.vision.VisionConstants +import frc.team449.robot2023.subsystems.ControllerBindings +import monologue.Logged +import monologue.Monologue +import monologue.Monologue.LogBoth +import kotlin.jvm.optionals.getOrNull + +/** The main class of the robot, constructs all the subsystems and initializes default commands. */ +class RobotLoop : TimedRobot(), Logged { + + @LogBoth + private val robot = Robot() + + private val routineChooser: RoutineChooser = RoutineChooser(robot) + + @LogBoth + private val field = robot.field + + private var autoCommand: Command? = null + private var routineMap = hashMapOf() + private val controllerBinder = ControllerBindings(robot.driveController, robot.mechController, robot) + + override fun robotInit() { + // Yes this should be a print statement, it's useful to know that robotInit started. + println("Started robotInit.") + + if (RobotBase.isSimulation()) { + // Don't complain about joysticks if there aren't going to be any + DriverStation.silenceJoystickConnectionWarning(true) +// val instance = NetworkTableInstance.getDefault() +// instance.stopServer() +// instance.startClient4("localhost") + } + + println("Generating Auto Routines : ${Timer.getFPGATimestamp()}") + routineMap = routineChooser.routineMap() + println("DONE Generating Auto Routines : ${Timer.getFPGATimestamp()}") + + SmartDashboard.putData("Routine Chooser", routineChooser) + SmartDashboard.putData("Command Scheduler", CommandScheduler.getInstance()) + SmartDashboard.putBoolean("Enable Logging?", false) + + robot.light.defaultCommand = BlairChasing(robot.light) + + controllerBinder.bindButtons() + + Monologue.setupLogging(this, "/Monologuing") + } + + override fun robotPeriodic() { + CommandScheduler.getInstance().run() + + robot.field.robotPose = robot.drive.pose + + robot.field.getObject("bumpers").pose = robot.drive.pose + + if (SmartDashboard.getBoolean("Enable Logging?", false)) { + Monologue.update() + } else if (RobotBase.isSimulation()) { + Monologue.updateNT() + } else { + Monologue.updateFileLog() + } + } + + override fun autonomousInit() { + /** Every time auto starts, we update the chosen auto command */ + this.autoCommand = routineMap[routineChooser.selected] + CommandScheduler.getInstance().schedule(this.autoCommand) + + if (DriverStation.getAlliance().getOrNull() == DriverStation.Alliance.Red) { + BreatheHue(robot.light, 0).schedule() + } else { + BreatheHue(robot.light, 95).schedule() + } + } + + override fun autonomousPeriodic() {} + + override fun teleopInit() { + if (autoCommand != null) { + CommandScheduler.getInstance().cancel(autoCommand) + } + + (robot.light.currentCommand ?: InstantCommand()).cancel() + + robot.drive.defaultCommand = robot.driveCommand + } + + override fun teleopPeriodic() { + } + + override fun disabledInit() { + robot.drive.stop() + + (robot.light.currentCommand ?: InstantCommand()).cancel() + Rainbow(robot.light).schedule() + } + + override fun disabledPeriodic() { + routineChooser.updateOptions(DriverStation.getAlliance().getOrNull() == DriverStation.Alliance.Red) + } + + override fun testInit() { + if (autoCommand != null) { + CommandScheduler.getInstance().cancel(autoCommand) + } + } + + override fun testPeriodic() {} + + override fun simulationInit() {} + + override fun simulationPeriodic() { + robot.drive as SwerveSim + + VisionConstants.ESTIMATORS.forEach { + it.simulationPeriodic(robot.drive.odoPose) + } + + VisionConstants.VISION_SIM.debugField.getObject("EstimatedRobot").pose = robot.drive.pose + } +} diff --git a/src/main/kotlin/frc/team449/control/DriveCommand.kt b/src/main/kotlin/frc/team449/control/DriveCommand.kt new file mode 100644 index 0000000..0047ecd --- /dev/null +++ b/src/main/kotlin/frc/team449/control/DriveCommand.kt @@ -0,0 +1,24 @@ +package frc.team449.control + +import edu.wpi.first.math.kinematics.ChassisSpeeds +import edu.wpi.first.wpilibj2.command.Command + +/** + * Generic driving command that applies the OI output to the drivetrain. + * @param drive The drivetrain to be controlled. + * @param oi The OI that feeds the inputted [ChassisSpeeds] to the [drive]. + */ +class DriveCommand( + private val drive: DriveSubsystem, + private val oi: OI +) : Command() { + + init { + addRequirements(drive) + } + + /** Take returned [ChassisSpeeds] from a joystick/[OI] and feed it to a [DriveSubsystem]. */ + override fun execute() { + drive.set(oi.get()) + } +} diff --git a/src/main/kotlin/frc/team449/control/DriveSubsystem.kt b/src/main/kotlin/frc/team449/control/DriveSubsystem.kt new file mode 100644 index 0000000..1c18479 --- /dev/null +++ b/src/main/kotlin/frc/team449/control/DriveSubsystem.kt @@ -0,0 +1,37 @@ +package frc.team449.control + +import edu.wpi.first.math.MathUtil +import edu.wpi.first.math.geometry.Pose2d +import edu.wpi.first.math.geometry.Rotation2d +import edu.wpi.first.math.geometry.Translation2d +import edu.wpi.first.math.kinematics.ChassisSpeeds +import edu.wpi.first.wpilibj2.command.Subsystem + +/** A drivetrain that uses closed-loop velocity control. */ +interface DriveSubsystem : Subsystem { + var heading: Rotation2d + get() = Rotation2d(MathUtil.angleModulus(this.pose.rotation.radians)) + set(value) { + this.pose = Pose2d(Translation2d(this.pose.x, this.pose.y), value) + } + + var pose: Pose2d + + /** Sets the drivetrain's desired speeds. */ + fun set(desiredSpeeds: ChassisSpeeds) + + /** Sets all the robot's drive motors to 0. */ + fun stop() + + /** + * Used to simulate a drivetrain. Only one instance of this class should be made per drivetrain. + */ + interface SimController { + fun update() + + /** + * Simulate the current drawn by the drivetrain + */ + fun getCurrentDraw(): Double + } +} diff --git a/src/main/kotlin/frc/team449/control/OI.kt b/src/main/kotlin/frc/team449/control/OI.kt new file mode 100644 index 0000000..2806da6 --- /dev/null +++ b/src/main/kotlin/frc/team449/control/OI.kt @@ -0,0 +1,11 @@ +package frc.team449.control + +import edu.wpi.first.math.kinematics.ChassisSpeeds + +/** + * An Operator Input (OI) that gets the desired [ChassisSpeeds] to give a [DriveSubsystem]. + */ + +fun interface OI { + fun get(): ChassisSpeeds +} diff --git a/src/main/kotlin/frc/team449/control/TrapezoidalExponentialProfile.kt b/src/main/kotlin/frc/team449/control/TrapezoidalExponentialProfile.kt new file mode 100644 index 0000000..7f1bba5 --- /dev/null +++ b/src/main/kotlin/frc/team449/control/TrapezoidalExponentialProfile.kt @@ -0,0 +1,300 @@ +package frc.team449.control + +import edu.wpi.first.math.util.Units +import frc.team449.robot2023.constants.MotorConstants +import kotlin.math.* + +// TODO: Copy parameter descriptions from Rafi's spreadsheet +// and figure out to do for current vel > 0 situations (ideas: don't do anything, or use a trap profile in that case idk) + +/** @param effectiveGearing is motor rotations : output rotations (should be greater than 1 if a reduction + * @param pulleyRadius in meters + * @param systemMass in kilograms + * @param angle in degrees + * @param tolerance in meters + * @param vMax user specified max speed in m/s + * @param startingDistance the start distance of the profile + * @param finalDistance the goal distance of the profile + * @param aStop the max negative acceleration of the profile + * @param efficiency percent efficiency of the system + */ +class TrapezoidalExponentialProfile( + pulleyRadius: Double, + currentLimit: Int, + numMotors: Int, + effectiveGearing: Double, + systemMass: Double, + angle: Double, + private val tolerance: Double = 0.05, + private val vMax: Double = 5.0, + startingDistance: Double = 0.0, + private var finalDistance: Double, + private var aStop: Double = 9.81, + efficiency: Double +) { + private val trueStartingDistance: Double = startingDistance + private val trueFinalDistance: Double = finalDistance + private var switchedStartingAndFinal: Boolean = false + + // NEO Motor Constants + val freeSpeed = MotorConstants.FREE_SPEED + val freeCurrent = MotorConstants.FREE_CURRENT + val stallCurrent = MotorConstants.STALL_CURRENT + val stallTorque = MotorConstants.STALL_TORQUE * efficiency + + private fun expDecelIntercept( + vFree: Double, + vLim: Double, + aLim: Double, + aStop: Double, + xF: Double, + x20: Double + ): Double { + val A = vFree + val B = -(vFree - vLim) + val C = -aLim / (vFree - vLim) + val D = 2 * aStop + val deltaX = xF - x20 + + var lastSeed = -5.0 + var seed = 0.0 + var seedVal = evaluateExp(A, B, C, D, deltaX, seed) + var seedDer = evaluateExpDerivative(A, B, C, D, seed) + + while (abs(seed - lastSeed) > 1e-4) { + lastSeed = seed + seed -= seedVal / seedDer + seedVal = evaluateExp(A, B, C, D, deltaX, seed) + seedDer = evaluateExpDerivative(A, B, C, D, seed) + + if (seedVal == 0.0) { + return 0.0 + } + + if (seedDer == 0.0) { + error("Newton method derivative is 0") + } + } + + return seed + } + + private fun evaluateExp( + A: Double, + B: Double, + C: Double, + D: Double, + deltaX: Double, + t: Double + ): Double { + return B.pow(2) * exp(2 * C * t) + (D * B / C + 2 * A * B) * exp(C * t) + A * D * t - D * B / C - deltaX * D + A.pow( + 2 + ) + } + + private fun evaluateExpDerivative( + A: Double, + B: Double, + C: Double, + D: Double, + t: Double + ): Double { + return 2 * B.pow(2) * C * exp(2 * C * t) + (B * D / C + 2 * A * B) * C * exp(C * t) + A * D + } + + private val vLim = + pulleyRadius * freeSpeed / effectiveGearing * (1 - (currentLimit - freeCurrent) / (stallCurrent - freeCurrent)) + private val effectiveStallTorque = stallTorque * numMotors + private val effectiveGravity = 9.81 * sin(Units.degreesToRadians(angle)) + private var aLim = + ((currentLimit - freeCurrent) / (stallCurrent - freeCurrent) * effectiveStallTorque * effectiveGearing) / (systemMass * pulleyRadius) - effectiveGravity + private val vFree = + pulleyRadius * freeSpeed / effectiveGearing * (1 - systemMass * effectiveGravity * pulleyRadius / effectiveGearing / effectiveStallTorque) + private val vMax2 = min(vMax, vFree) + + init { + if (startingDistance > finalDistance) { + finalDistance = trueStartingDistance - trueFinalDistance + val buffer = aStop + aStop = aLim + aLim = buffer + switchedStartingAndFinal = true + } else if (startingDistance > 0) { + finalDistance = trueFinalDistance - trueStartingDistance + } + } + + private val t12 = vLim / aLim + private val t13 = vMax2 / aLim + private val t14 = sqrt(2 * finalDistance / (aLim + aLim.pow(2) / aStop)) + private val t1f = min(t14, min(t12, t13)) + private val x1f = 0.5 * aLim * t1f.pow(2) + private val v1f = aLim * t1f + + private val ENTER_EXP = t12 < t13 && t12 < t14 + private val t20 = if (ENTER_EXP) t12 else Double.NaN + private val x20 = if (ENTER_EXP) x1f else Double.NaN + private val v20 = if (ENTER_EXP) v1f else Double.NaN + private val dt23 = + if ((vFree - vMax2) / (vFree - vLim) > 0) -(vFree - vLim) / aLim * ln((vFree - vMax2) / (vFree - vLim)) else Double.NaN + private val dt24 = if (ENTER_EXP) expDecelIntercept(vFree, vLim, aLim, aStop, finalDistance, x20) else Double.NaN + private val t2f = t20 + if (!dt23.isNaN() && !dt24.isNaN()) min(dt23, dt24) else if (!dt24.isNaN()) dt24 else 0.0 + private val x2f = + x20 + vFree * (t2f - t20) + (vFree - vLim).pow(2) / aLim * (exp(-aLim / (vFree - vLim) * (t2f - t20)) - 1) + private val v2f = vFree - (vFree - vLim) * exp(-aLim / (vFree - vLim) * (t2f - t20)) + private val ENTER_COAST = + if (ENTER_EXP) { + if (!dt23.isNaN() && !dt24.isNaN()) { + dt24 > dt23 + } else { + false + } + } else { + t14 > t13 + } + + private val t30 = + if (ENTER_COAST) { + if (ENTER_EXP) { + t2f + } else { + t13 + } + } else { + Double.NaN + } + + private val x30 = + if (ENTER_COAST) { + if (ENTER_EXP) { + x2f + } else { + x1f + } + } else { + Double.NaN + } + + private val v30 = + if (ENTER_COAST) { + if (ENTER_EXP) { + v2f + } else { + v1f + } + } else { + Double.NaN + } + + private val dt34 = if (!x30.isNaN()) (finalDistance - x30) - vMax2 - vMax2 / 2 / aStop else Double.NaN + private val t3f = if (!dt34.isNaN() && !t30.isNaN()) dt34 + t30 else Double.NaN + private val x3f = if (!x30.isNaN() && !dt34.isNaN()) x30 + vMax2 * dt34 else Double.NaN + private val v3f = vMax2 + + private val t40 = if (ENTER_COAST) t3f else if (ENTER_EXP) t2f else t14 + private val x40 = if (ENTER_COAST) x3f else if (ENTER_EXP) x2f else x1f + private val v40 = if (ENTER_COAST) v3f else if (ENTER_EXP) v2f else v1f + private val t4f = t40 + v40 / aStop + private val x4f = x40 + v40 * (t4f - t40) - 0.5 * aStop * (t4f - t40).pow(2) + private val v4f = v40 - aStop * (t4f - t40) + + val finalTime = t4f + + private fun sample1(t: Double): Pair { + return if (switchedStartingAndFinal) { + Pair( + trueStartingDistance - (0.5 * aLim * t.pow(2)), + -(aLim * t) + ) + } else { + Pair( + 0.5 * aLim * t.pow(2) + trueStartingDistance, + aLim * t + ) + } + } + + private fun sample2(t: Double): Pair { + return if (switchedStartingAndFinal) { + Pair( + trueStartingDistance - (x20 + vFree * (t - t20) + (vFree - vLim).pow(2) / aLim * (exp(-aLim / (vFree - vLim) * (t - t20)) - 1)), + -(vFree - (vFree - vLim) * exp(-aLim / (vFree - vLim) * (t - t20))) + ) + } else { + Pair( + x20 + vFree * (t - t20) + (vFree - vLim).pow(2) / aLim * (exp(-aLim / (vFree - vLim) * (t - t20)) - 1) + trueStartingDistance, + vFree - (vFree - vLim) * exp(-aLim / (vFree - vLim) * (t - t20)) + ) + } + } + + private fun sample3(t: Double): Pair { + return if (switchedStartingAndFinal) { + Pair( + // hey, this was vMax in this script. Shouldn't this be vMax2 for the actual top speed? + trueStartingDistance - (x30 + vMax2 * (t - t30)), + -vMax + ) + } else { + Pair( + // hey, this was vMax in this script. Shouldn't this be vMax2 for the actual top speed? + x30 + vMax2 * (t - t30) + trueStartingDistance, + vMax + ) + } + } + + private fun sample4(t: Double): Pair { + return if (switchedStartingAndFinal) { + Pair( + trueStartingDistance - (x40 + v40 * (t - t40) - 0.5 * aStop * (t - t40).pow(2)), + -(v40 - aStop * (t - t40)) + ) + } else { + Pair( + x40 + v40 * (t - t40) - 0.5 * aStop * (t - t40).pow(2) + trueStartingDistance, + v40 - aStop * (t - t40) + ) + } + } + + fun calculate(t: Double): Pair { + if (abs(trueFinalDistance - trueStartingDistance) < tolerance) return Pair(trueFinalDistance, 0.0) + + if (t <= 0.0) return Pair(trueStartingDistance, 0.0) + + if (t >= t4f) return Pair(trueFinalDistance, 0.0) + + if (t <= t1f) { + return sample1(t) + } + + if (ENTER_EXP) { + return if (ENTER_COAST) { + if (t <= t2f) { + sample2(t) + } else if (t <= t3f) { + sample3(t) + } else { + sample4(t) + } + } else { + if (t <= t2f) { + sample2(t) + } else { + sample4(t) + } + } + } else { + return if (ENTER_COAST) { + if (t <= t3f) { + sample3(t) + } else { + sample4(t) + } + } else { + sample4(t) + } + } + } +} diff --git a/src/main/kotlin/frc/team449/control/auto/ChoreoFollower.kt b/src/main/kotlin/frc/team449/control/auto/ChoreoFollower.kt new file mode 100644 index 0000000..c615ee9 --- /dev/null +++ b/src/main/kotlin/frc/team449/control/auto/ChoreoFollower.kt @@ -0,0 +1,91 @@ +package frc.team449.control.auto + +import edu.wpi.first.math.controller.PIDController +import edu.wpi.first.math.geometry.Pose2d +import edu.wpi.first.math.geometry.Rotation2d +import edu.wpi.first.math.kinematics.ChassisSpeeds +import edu.wpi.first.wpilibj.Timer +import edu.wpi.first.wpilibj2.command.Command +import frc.team449.control.holonomic.HolonomicDrive +import frc.team449.robot2023.constants.auto.AutoConstants +import kotlin.math.PI + +class ChoreoFollower( + private val drivetrain: HolonomicDrive, + private val trajectory: ChoreoTrajectory, + private val xController: PIDController = PIDController(AutoConstants.DEFAULT_X_KP, 0.0, 0.0), + private val yController: PIDController = PIDController(AutoConstants.DEFAULT_Y_KP, 0.0, 0.0), + private val thetaController: PIDController = PIDController(AutoConstants.DEFAULT_ROTATION_KP, 0.0, 0.0), + poseTol: Pose2d = Pose2d(0.035, 0.035, Rotation2d(0.035)), + private val timeout: Double = 0.65, + private val resetPose: Boolean = false, + private val debug: Boolean = false +) : Command() { + + private val timer = Timer() + + init { + addRequirements(drivetrain) + + xController.reset() + xController.setTolerance(poseTol.x) + + yController.reset() + yController.setTolerance(poseTol.y) + + thetaController.reset() + thetaController.enableContinuousInput(-PI, PI) + thetaController.setTolerance(poseTol.rotation.radians) + } + + private fun calculate(currPose: Pose2d, desState: ChoreoTrajectory.ChoreoState): ChassisSpeeds { + val xFF = desState.xVel + val yFF = desState.yVel + val angFF = desState.thetaVel + + val xPID = xController.calculate(currPose.x, desState.xPos) + val yPID = yController.calculate(currPose.y, desState.yPos) + val angPID = thetaController.calculate(currPose.rotation.radians, desState.theta) + + return if (debug) { + ChassisSpeeds.fromFieldRelativeSpeeds(xFF, yFF, angFF, currPose.rotation) + } else { + ChassisSpeeds.fromFieldRelativeSpeeds(xFF + xPID, yFF + yPID, angFF + angPID, currPose.rotation) + } + } + + private fun allControllersAtReference(): Boolean { + return xController.atSetpoint() && yController.atSetpoint() && thetaController.atSetpoint() + } + + override fun initialize() { + xController.reset() + yController.reset() + thetaController.reset() + + if (resetPose) { + drivetrain.pose = trajectory.initialPose() + } + + timer.restart() + } + + override fun execute() { + val currTime = timer.get() + + val desiredMatrix = trajectory.sample(currTime) + + drivetrain.set(calculate(drivetrain.pose, desiredMatrix)) + } + + override fun isFinished(): Boolean { + return (timer.hasElapsed(trajectory.totalTime) && allControllersAtReference()) || + timer.hasElapsed(trajectory.totalTime + timeout) + } + + override fun end(interrupted: Boolean) { + timer.stop() + timer.reset() + drivetrain.stop() + } +} diff --git a/src/main/kotlin/frc/team449/control/auto/ChoreoRoutine.kt b/src/main/kotlin/frc/team449/control/auto/ChoreoRoutine.kt new file mode 100644 index 0000000..c1e159e --- /dev/null +++ b/src/main/kotlin/frc/team449/control/auto/ChoreoRoutine.kt @@ -0,0 +1,66 @@ +package frc.team449.control.auto + +import edu.wpi.first.math.controller.PIDController +import edu.wpi.first.math.geometry.Pose2d +import edu.wpi.first.math.geometry.Rotation2d +import edu.wpi.first.wpilibj2.command.* +import frc.team449.control.holonomic.HolonomicDrive +import frc.team449.robot2023.constants.auto.AutoConstants +import kotlin.math.abs + +class ChoreoRoutine( + private val xController: PIDController = PIDController(AutoConstants.DEFAULT_X_KP, 0.0, 0.0), + private val yController: PIDController = PIDController(AutoConstants.DEFAULT_Y_KP, 0.0, 0.0), + private val thetaController: PIDController = PIDController(AutoConstants.DEFAULT_ROTATION_KP, 0.0, 0.0), + private val drive: HolonomicDrive, + private val stopEventMap: HashMap = HashMap(), + private val parallelEventMap: HashMap = HashMap(), + private val poseTol: Pose2d = Pose2d(0.05, 0.05, Rotation2d.fromDegrees(1.5)), + private val resetPosition: Boolean = false, + private val resetPositionTolerance: Pose2d = Pose2d(0.0, 0.0, Rotation2d.fromDegrees(0.0)), + private val timeout: Double = 1.5, + private val debug: Boolean = false +) { + + private fun resetPose(trajectory: ChoreoTrajectory): Command { + val poseError = drive.pose.relativeTo(trajectory.initialPose()) + + if (abs(poseError.x) < resetPositionTolerance.x && + abs(poseError.y) < resetPositionTolerance.y && + abs(poseError.rotation.radians) < resetPositionTolerance.rotation.radians + ) { + return PrintCommand("Pose not reset.") + } + + return InstantCommand({ drive.pose = trajectory.initialPose() }) + } + + fun createRoutine(trajectories: MutableList): Command { + val ezraGallun = SequentialCommandGroup( + resetPose(trajectories[0]), + stopEventMap.getOrDefault(0, InstantCommand()) + ) + + for (i in 0 until trajectories.size) { + ezraGallun.addCommands( + ParallelDeadlineGroup( + ChoreoFollower( + drive, + trajectories[i], + xController, + yController, + thetaController, + poseTol, + timeout, + resetPosition, + debug + ), + parallelEventMap.getOrDefault(i, InstantCommand()) + ) + ) + ezraGallun.addCommands(stopEventMap.getOrDefault(i + 1, InstantCommand())) + } + + return ezraGallun + } +} diff --git a/src/main/kotlin/frc/team449/control/auto/ChoreoRoutineStructure.kt b/src/main/kotlin/frc/team449/control/auto/ChoreoRoutineStructure.kt new file mode 100644 index 0000000..6ddd877 --- /dev/null +++ b/src/main/kotlin/frc/team449/control/auto/ChoreoRoutineStructure.kt @@ -0,0 +1,14 @@ +package frc.team449.control.auto + +import edu.wpi.first.wpilibj2.command.Command + +interface ChoreoRoutineStructure { + + val routine: ChoreoRoutine + + val trajectory: MutableList + + fun createCommand(): Command { + return routine.createRoutine(trajectory) + } +} diff --git a/src/main/kotlin/frc/team449/control/auto/ChoreoTrajectory.kt b/src/main/kotlin/frc/team449/control/auto/ChoreoTrajectory.kt new file mode 100644 index 0000000..df8c669 --- /dev/null +++ b/src/main/kotlin/frc/team449/control/auto/ChoreoTrajectory.kt @@ -0,0 +1,116 @@ +package frc.team449.control.auto + +import edu.wpi.first.math.InterpolatingMatrixTreeMap +import edu.wpi.first.math.MatBuilder +import edu.wpi.first.math.MathUtil +import edu.wpi.first.math.geometry.Pose2d +import edu.wpi.first.math.geometry.Rotation2d +import edu.wpi.first.math.numbers.N2 +import edu.wpi.first.math.numbers.N3 +import edu.wpi.first.wpilibj.Filesystem +import org.json.simple.JSONArray +import org.json.simple.JSONObject +import org.json.simple.parser.JSONParser +import java.io.File +import java.io.FileReader + +class ChoreoTrajectory( + val name: String, + val stateMap: InterpolatingMatrixTreeMap, + val totalTime: Double, + val objectiveTimestamps: ArrayList +) { + + fun initialPose(): Pose2d { + val initialState = stateMap.get(0.0) + + return Pose2d( + initialState[0, 0], + initialState[0, 1], + Rotation2d(initialState[0, 2]) + ) + } + + fun sample(t: Double): ChoreoState { + val timeSeconds = MathUtil.clamp(t, 0.0, totalTime) + val interpolatedMat = stateMap.get(timeSeconds) + + return ChoreoState( + interpolatedMat[0, 0], + interpolatedMat[0, 1], + interpolatedMat[0, 2], + interpolatedMat[1, 0], + interpolatedMat[1, 1], + interpolatedMat[1, 2] + ) + } + + class ChoreoState( + val xPos: Double, + val yPos: Double, + val theta: Double, + val xVel: Double, + val yVel: Double, + val thetaVel: Double + ) + + companion object { + fun createTrajectory( + filename: String + ): MutableList { + val path = Filesystem.getDeployDirectory().absolutePath.plus("/choreo/$filename.chor") + val document = (JSONParser().parse(FileReader(File(path).absolutePath)) as JSONObject)["paths"] as HashMap<*, *> + + val trajList = mutableListOf() + + document.forEach { (name, pathData) -> + name as String + pathData as JSONObject + val trajectory = pathData["trajectory"] as JSONArray + + val info = parse(trajectory) + + val last = trajectory.last() as JSONObject + val totalTime = last["timestamp"] as Double + + trajList.add( + ChoreoTrajectory( + filename + name, + info.first, + totalTime, + info.second + ) + ) + } + + return trajList + } + + private fun parse(trajectory: JSONArray): Pair, ArrayList> { + val stateMap = InterpolatingMatrixTreeMap() + + val timestamps = arrayListOf() + + trajectory.forEach { state -> + state as JSONObject + val stateTime = state["timestamp"].toString().toDouble() + + timestamps.add(stateTime) + + val builder = MatBuilder(N2.instance, N3.instance) + val matrix = builder.fill( + state["x"].toString().toDouble(), + state["y"].toString().toDouble(), + state["heading"].toString().toDouble(), + state["velocityX"].toString().toDouble(), + state["velocityY"].toString().toDouble(), + state["angularVelocity"].toString().toDouble() + ) + + stateMap.put(stateTime, matrix) + } + + return stateMap to timestamps + } + } +} diff --git a/src/main/kotlin/frc/team449/control/differential/DifferentialDrive.kt b/src/main/kotlin/frc/team449/control/differential/DifferentialDrive.kt new file mode 100644 index 0000000..3cf0e19 --- /dev/null +++ b/src/main/kotlin/frc/team449/control/differential/DifferentialDrive.kt @@ -0,0 +1,212 @@ +package frc.team449.control.differential + +import edu.wpi.first.math.controller.DifferentialDriveFeedforward +import edu.wpi.first.math.controller.PIDController +import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator +import edu.wpi.first.math.geometry.Pose2d +import edu.wpi.first.math.kinematics.ChassisSpeeds +import edu.wpi.first.math.kinematics.DifferentialDriveKinematics +import edu.wpi.first.math.kinematics.DifferentialDriveWheelSpeeds +import edu.wpi.first.wpilibj.Timer +import edu.wpi.first.wpilibj2.command.SubsystemBase +import frc.team449.control.DriveSubsystem +import frc.team449.robot2023.constants.RobotConstants +import frc.team449.robot2023.constants.drives.DifferentialConstants +import frc.team449.system.AHRS +import frc.team449.system.encoder.QuadEncoder +import frc.team449.system.motor.WrappedMotor +import frc.team449.system.motor.createSparkMax + +/** + * A differential drive (aka. tank drive). + * @param leftLeader The lead motor of the left side. + * @param rightLeader The lead motor of the right side. + * @param ahrs The gyro that is mounted on the chassis. + * @param feedForward The differential drive feed forward used for calculating the side voltages. + * @param makeSidePID Used to make two copies of the same PID controller to control both sides of the robot. + * @param trackwidth The distance between the two wheel sides of the robot. + */ +open class DifferentialDrive( + private val leftLeader: WrappedMotor, + private val rightLeader: WrappedMotor, + private val ahrs: AHRS, + private val feedForward: DifferentialDriveFeedforward, + private val makeSidePID: () -> PIDController, + private val trackwidth: Double +) : DriveSubsystem, SubsystemBase() { + init { + leftLeader.encoder.resetPosition(0.0) + rightLeader.encoder.resetPosition(0.0) + } + + /** Kinematics used to convert [ChassisSpeeds] to [DifferentialDriveWheelSpeeds] */ + val kinematics = DifferentialDriveKinematics(trackwidth) + + /** Pose estimator that estimates the robot's position as a [Pose2d]. */ + val poseEstimator = DifferentialDrivePoseEstimator( + kinematics, + ahrs.heading, + leftLeader.position, + rightLeader.position, + Pose2d() + ) + + /** Velocity PID controller for left side. */ + private val leftPID = makeSidePID() + + /** Velocity PID controller for right side. */ + private val rightPID = makeSidePID() + + var desiredWheelSpeeds = DifferentialDriveWheelSpeeds(0.0, 0.0) + + private var previousTime = Double.NaN + private var prevWheelSpeeds = DifferentialDriveWheelSpeeds(0.0, 0.0) + + private var prevLeftVel = 0.0 + private var prevRightVel = 0.0 + private var leftVel = 0.0 + private var rightVel = 0.0 + + /** Calculate left and right side speeds from given [ChassisSpeeds]. */ + override fun set(desiredSpeeds: ChassisSpeeds) { + prevWheelSpeeds = desiredWheelSpeeds + + prevLeftVel = desiredWheelSpeeds.leftMetersPerSecond + prevRightVel = desiredWheelSpeeds.rightMetersPerSecond + + desiredWheelSpeeds = kinematics.toWheelSpeeds(desiredSpeeds) + desiredWheelSpeeds.desaturate(RobotConstants.MAX_LINEAR_SPEED) + + leftVel = desiredWheelSpeeds.leftMetersPerSecond + rightVel = desiredWheelSpeeds.rightMetersPerSecond + } + + /** The (x, y, theta) position of the robot on the field. */ + override var pose: Pose2d + get() = this.poseEstimator.estimatedPosition + set(pose) { + leftLeader.encoder.resetPosition(0.0) + rightLeader.encoder.resetPosition(0.0) + this.poseEstimator.resetPosition(ahrs.heading, leftLeader.position, rightLeader.position, pose) + } + + override fun stop() { + this.set(ChassisSpeeds(0.0, 0.0, 0.0)) + } + + override fun periodic() { + val currentTime = Timer.getFPGATimestamp() + + val dt = if (previousTime.isNaN()) 0.02 else currentTime - previousTime + + leftPID.setpoint = leftVel + rightPID.setpoint = rightVel + + /** Calculates the individual side voltages using a [DifferentialDriveFeedforward]. */ + val sideVoltages = feedForward.calculate( + prevLeftVel, + leftVel, + prevRightVel, + rightVel, + dt + ) + + leftLeader.setVoltage(sideVoltages.left + leftPID.calculate(prevLeftVel)) + + rightLeader.setVoltage(sideVoltages.right + rightPID.calculate(prevRightVel)) + + this.poseEstimator.update(ahrs.heading, this.leftLeader.position, this.rightLeader.position) + + previousTime = currentTime + } + + companion object { + /** Create a [DifferentialDrive] using [DifferentialConstants]. */ + private fun makeSide( + name: String, + motorId: Int, + inverted: Boolean, + encInverted: Boolean, + wpiEnc: edu.wpi.first.wpilibj.Encoder, + followers: Map + ) = + createSparkMax( + name = name + "_Side", + id = motorId, + enableBrakeMode = true, + inverted = inverted, + encCreator = QuadEncoder.creator( + wpiEnc, + DifferentialConstants.DRIVE_EXT_ENC_CPR, + DifferentialConstants.DRIVE_UPR, + DifferentialConstants.DRIVE_GEARING, + encInverted + ), + + slaveSparks = followers, + currentLimit = DifferentialConstants.DRIVE_CURRENT_LIM + ) + + fun createDifferentialDrive(ahrs: AHRS): DifferentialDrive { + return DifferentialDrive( + leftLeader = makeSide( + "Left", + DifferentialConstants.DRIVE_MOTOR_L, + inverted = false, + encInverted = false, + wpiEnc = DifferentialConstants.DRIVE_ENC_LEFT, + followers = mapOf( + DifferentialConstants.DRIVE_MOTOR_L1 to false, + DifferentialConstants.DRIVE_MOTOR_L2 to false + ) + ), + rightLeader = makeSide( + "Right", + DifferentialConstants.DRIVE_MOTOR_R, + inverted = true, + encInverted = true, + wpiEnc = DifferentialConstants.DRIVE_ENC_RIGHT, + followers = mapOf( + DifferentialConstants.DRIVE_MOTOR_R1 to false, + DifferentialConstants.DRIVE_MOTOR_R2 to false + ) + ), + ahrs, + DifferentialConstants.DRIVE_FEED_FORWARD, + { + PIDController( + DifferentialConstants.DRIVE_KP, + DifferentialConstants.DRIVE_KI, + DifferentialConstants.DRIVE_KD + ) + }, + DifferentialConstants.TRACK_WIDTH + ) + } + +// fun simOf( +// drive: DifferentialDrive, +// kV: Double, +// kA: Double, +// angleKV: Double, +// angleKA: Double, +// wheelRadius: Double +// ): DifferentialSim { +// val drivePlant = LinearSystemId.identifyDrivetrainSystem( +// kV, +// kA, +// angleKV, +// angleKA +// ) +// val driveSim = DifferentialDrivetrainSim( +// drivePlant, +// DCMotor.getNEO(3), +// DifferentialConstants.DRIVE_GEARING, +// drive.trackwidth, +// wheelRadius, +// VecBuilder.fill(0.001, 0.001, 0.001, 0.1, 0.1, 0.005, 0.005) +// ) +// return DifferentialSim(driveSim, drive.leftLeader, drive.rightLeader, drive.ahrs, drive.feedforward, drive.makeVelPID, drive.trackwidth) +// } + } +} diff --git a/src/main/kotlin/frc/team449/control/differential/DifferentialOIs.kt b/src/main/kotlin/frc/team449/control/differential/DifferentialOIs.kt new file mode 100644 index 0000000..6fe4957 --- /dev/null +++ b/src/main/kotlin/frc/team449/control/differential/DifferentialOIs.kt @@ -0,0 +1,140 @@ +package frc.team449.control.differential + +import edu.wpi.first.math.filter.SlewRateLimiter +import edu.wpi.first.math.kinematics.ChassisSpeeds +import edu.wpi.first.math.kinematics.DifferentialDriveKinematics +import edu.wpi.first.math.kinematics.DifferentialDriveWheelSpeeds +import edu.wpi.first.wpilibj.drive.DifferentialDrive.WheelSpeeds +import frc.team449.control.OI +import frc.team449.robot2023.constants.RobotConstants + +/** + * Helper class to create OIs for a differential drivetrain (arcade, curvature, + * or tank) + */ +object DifferentialOIs { + /** + * Create an OI for arcade drive. One throttle controls forward-backward speed, + * the other; controls rotation. + * + * @param drive The drivetrain + * @param xThrottle Throttle to get forward-backward movement + * @param rotThrottle Throttle to get rotation + * @param xRamp Used for limiting forward-backward acceleration + * @param rotRamp Used for limiting rotational acceleration + */ + fun createArcade( + drive: DifferentialDrive, + xThrottle: () -> Double, + rotThrottle: () -> Double, + xRamp: SlewRateLimiter, + rotRamp: SlewRateLimiter + ): OI = OI { + scaleAndApplyRamping( + edu.wpi.first.wpilibj.drive.DifferentialDrive.arcadeDriveIK( + xThrottle(), + rotThrottle(), + false + ), + drive.kinematics, + xRamp, + rotRamp + ) + } + + /** + * Create OI for curvature drive (drives like a car). One throttle controls + * forward-backward speed, like arcade, but the other controls curvature instead + * of rotation. Ramping is still applied to rotation instead of curvature. + * + * @param drive The drivetrain + * @param xThrottle Throttle to get forward-backward movement + * @param rotThrottle Throttle to get rotation + * @param xRamp Used for limiting forward-backward acceleration + * @param rotRamp Used for limiting rotational acceleration + * @param turnInPlace When this returns true, turns in place instead of turning + * like a car + */ + fun createCurvature( + drive: DifferentialDrive, + xThrottle: () -> Double, + rotThrottle: () -> Double, + xRamp: SlewRateLimiter, + rotRamp: SlewRateLimiter, + turnInPlace: () -> Boolean + ): OI = OI { + scaleAndApplyRamping( + edu.wpi.first.wpilibj.drive.DifferentialDrive.curvatureDriveIK( + xThrottle(), + rotThrottle(), + turnInPlace() + ), + drive.kinematics, + xRamp, + rotRamp + ) + } + + /** + * Create an OI for tank drive. Each throttle controls one side of the drive + * separately. Each side is also ramped separately. + * + *

+ * Shame on you if you ever use this. + * + * @param drive The drivetrain + * @param leftThrottle Throttle to get forward-backward movement + * @param rightThrottle Throttle to get rotation + * @param leftRamp Used for limiting the left side's acceleration + * @param rightRamp Used for limiting the right side's acceleration + */ + fun createTank( + drive: DifferentialDrive, + leftThrottle: () -> Double, + rightThrottle: () -> Double, + leftRamp: SlewRateLimiter, + rightRamp: SlewRateLimiter + ): OI = OI { + drive.kinematics.toChassisSpeeds( + DifferentialDriveWheelSpeeds( + leftRamp.calculate(leftThrottle() * RobotConstants.MAX_LINEAR_SPEED), + rightRamp.calculate( + rightThrottle() * RobotConstants.MAX_LINEAR_SPEED + ) + ) + ) + } + + /** + * Scales differential drive throttles from [-1, 1] to [-maxSpeed, maxSpeed], then + * applies ramping to give the final [ChassisSpeeds]. + * + *

+ * Do note that although this is given a [DifferentialDriveWheelSpeeds] + * object, the ramping isn't applied to the left and right side but to the + * linear and rotational velocity using a [ChassisSpeeds] object. + * + * @param wheelThrottles The left and right wheel throttles + * @param kinematics Kinematics object used for turning differential drive wheel + * speeds to chassis speeds + * @param ramp Used for limiting linear/forward-back acceleration + * @param rotRamp Used for limiting rotational acceleration + */ + private fun scaleAndApplyRamping( + wheelThrottles: WheelSpeeds, + kinematics: DifferentialDriveKinematics, + ramp: SlewRateLimiter, + rotRamp: SlewRateLimiter + ): ChassisSpeeds { + val leftVel = wheelThrottles.left * RobotConstants.MAX_LINEAR_SPEED + val rightVel = wheelThrottles.right * RobotConstants.MAX_LINEAR_SPEED + val chassisSpeeds = kinematics.toChassisSpeeds( + DifferentialDriveWheelSpeeds(leftVel, rightVel) + ) + return ChassisSpeeds( + ramp.calculate(chassisSpeeds.vxMetersPerSecond), + 0.0, + rotRamp.calculate(chassisSpeeds.omegaRadiansPerSecond) + ) + } +} diff --git a/src/main/kotlin/frc/team449/control/differential/DifferentialSim.kt b/src/main/kotlin/frc/team449/control/differential/DifferentialSim.kt new file mode 100644 index 0000000..6687e6f --- /dev/null +++ b/src/main/kotlin/frc/team449/control/differential/DifferentialSim.kt @@ -0,0 +1,66 @@ +package frc.team449.control.differential + +// import edu.wpi.first.math.controller.DifferentialDriveFeedforward +// import edu.wpi.first.math.controller.PIDController +// import edu.wpi.first.math.controller.SimpleMotorFeedforward +// import edu.wpi.first.math.geometry.Pose2d +// import edu.wpi.first.math.geometry.Rotation2d +// import edu.wpi.first.wpilibj.Timer +// import edu.wpi.first.wpilibj.simulation.DifferentialDrivetrainSim +// import frc.team449.system.AHRS +// import frc.team449.system.encoder.Encoder +// import frc.team449.system.motor.WrappedMotor +// +// class DifferentialSim( +// private val driveSim: DifferentialDrivetrainSim, +// leftLeader: WrappedMotor, +// rightLeader: WrappedMotor, +// ahrs: AHRS, +// private val feedForward: DifferentialDriveFeedforward, +// makeVelPID: () -> PIDController, +// trackwidth: Double +// ) : DifferentialDrive(leftLeader, rightLeader, ahrs, feedForward, makeVelPID, trackwidth) { +// +// private val leftEncSim = Encoder.SimController(leftLeader.encoder) +// private val rightEncSim = Encoder.SimController(rightLeader.encoder) +// +// private var offset: Rotation2d = Rotation2d() +// private var lastTime = Timer.getFPGATimestamp() +// +// override fun periodic() { +// val currTime = Timer.getFPGATimestamp() +// +// val dt = currTime - lastTime +// +// val leftVel = desiredWheelSpeeds.leftMetersPerSecond +// val rightVel = desiredWheelSpeeds.rightMetersPerSecond +// +// val sideVoltages = feedForward.calculate() +// +// val leftVoltage = feedForward.calculate(leftVel) + leftPID.calculate(driveSim.leftVelocityMetersPerSecond, leftVel) +// val rightVoltage = feedForward.calculate(rightVel) + rightPID.calculate(driveSim.rightVelocityMetersPerSecond, rightVel) +// +// leftEncSim.velocity = driveSim.leftVelocityMetersPerSecond +// rightEncSim.velocity = driveSim.rightVelocityMetersPerSecond +// leftEncSim.position = driveSim.leftPositionMeters +// rightEncSim.position = driveSim.rightPositionMeters +// +// driveSim.setInputs(leftVoltage, rightVoltage) +// +// driveSim.update(dt) +// this.poseEstimator.update(heading, this.leftEncSim.position, this.rightEncSim.position) +// this.lastTime = currTime +// } +// +// override var pose: Pose2d +// get() = driveSim.pose +// set(value) { +// driveSim.pose = value +// } +// +// override var heading: Rotation2d +// get() = driveSim.heading.rotateBy(offset) +// set(value) { +// offset = value - driveSim.heading +// } +// } diff --git a/src/main/kotlin/frc/team449/control/holonomic/HolonomicDrive.kt b/src/main/kotlin/frc/team449/control/holonomic/HolonomicDrive.kt new file mode 100644 index 0000000..7856dda --- /dev/null +++ b/src/main/kotlin/frc/team449/control/holonomic/HolonomicDrive.kt @@ -0,0 +1,11 @@ +package frc.team449.control.holonomic + +import frc.team449.control.DriveSubsystem + +interface HolonomicDrive : DriveSubsystem { + /** The max speed that the drivetrain can translate at, in meters per second. */ + var maxLinearSpeed: Double + + /** The max speed that the drivetrain can turn in place at, in radians per second. */ + var maxRotSpeed: Double +} diff --git a/src/main/kotlin/frc/team449/control/holonomic/HolonomicOI.kt b/src/main/kotlin/frc/team449/control/holonomic/HolonomicOI.kt new file mode 100644 index 0000000..11e3a03 --- /dev/null +++ b/src/main/kotlin/frc/team449/control/holonomic/HolonomicOI.kt @@ -0,0 +1,141 @@ +package frc.team449.control.holonomic + +import edu.wpi.first.math.MathUtil +import edu.wpi.first.math.filter.SlewRateLimiter +import edu.wpi.first.math.geometry.Rotation2d +import edu.wpi.first.math.geometry.Translation2d +import edu.wpi.first.math.kinematics.ChassisSpeeds +import edu.wpi.first.util.sendable.Sendable +import edu.wpi.first.util.sendable.SendableBuilder +import edu.wpi.first.wpilibj.Timer +import edu.wpi.first.wpilibj.XboxController +import frc.team449.control.OI +import frc.team449.robot2023.constants.RobotConstants +import java.util.function.DoubleSupplier +import kotlin.math.abs +import kotlin.math.hypot + +/** + * Create an OI for controlling a holonomic drivetrain (probably swerve). + * The x and y axes on one joystick are used to control x and y velocity (m/s), + * while the x axis on another joystick is used to control rotational velocity (m/s). + *

The magnitude of the acceleration is clamped + *

Note that the joystick's X + * axis corresponds to the robot's/field's Y and vice versa + * + * @param drive The drivetrain this OI is controlling + * @param xThrottle The Y axis of the strafing joystick + * @param yThrottle The X axis of the strafing joystick + * @param rotThrottle The X axis of the rotating joystick + * @param rotRamp Used to ramp angular velocity + * @param maxAccel Max accel, used for ramping + * @param fieldOriented Whether the OI x and y translation should + * be relative to the field rather than relative to the robot. This better be true. + */ +class HolonomicOI( + private val drive: HolonomicDrive, + private val xThrottle: DoubleSupplier, + private val yThrottle: DoubleSupplier, + private val rotThrottle: DoubleSupplier, + private val rotRamp: SlewRateLimiter, + private val maxAccel: Double, + private val fieldOriented: () -> Boolean +) : OI, Sendable { + + /** Previous X velocity (scaled and clamped). */ + private var prevX = 0.0 + + /** Previous Y velocity (scaled and clamped) */ + private var prevY = 0.0 + + private var prevTime = Double.NaN + + private var dx = 0.0 + private var dy = 0.0 + private var magAcc = 0.0 + private var dt = 0.0 + private var magAccClamped = 0.0 + + /** + * @return The [ChassisSpeeds] for the given x, y and + * rotation input from the joystick */ + override fun get(): ChassisSpeeds { + val currTime = Timer.getFPGATimestamp() + if (this.prevTime.isNaN()) { + this.prevTime = currTime - 0.02 + } + this.dt = currTime - prevTime + this.prevTime = currTime + + val xScaled = xThrottle.asDouble * drive.maxLinearSpeed + val yScaled = yThrottle.asDouble * drive.maxLinearSpeed + + // Clamp the acceleration + this.dx = xScaled - this.prevX + this.dy = yScaled - this.prevY + this.magAcc = hypot(dx / dt, dy / dt) + this.magAccClamped = MathUtil.clamp(magAcc, -this.maxAccel, this.maxAccel) + + // Scale the change in x and y the same as the acceleration + val factor = if (magAcc == 0.0) 0.0 else magAccClamped / magAcc + val dxClamped = dx * factor + val dyClamped = dy * factor + val xClamped = prevX + dxClamped + val yClamped = prevY + dyClamped + + this.prevX = xClamped + this.prevY = yClamped + + val rotRaw = rotThrottle.asDouble + val rotScaled = rotRamp.calculate(rotRaw * drive.maxRotSpeed) + + // translation velocity vector + val vel = Translation2d(xClamped, yClamped) + + return if (this.fieldOriented()) { + /** Quick fix for the velocity skewing towards the direction of rotation + * by rotating it with offset proportional to how much we are rotating + **/ + vel.rotateBy(Rotation2d(-rotScaled * dt / 2)) + ChassisSpeeds.fromFieldRelativeSpeeds( + vel.x, + vel.y, + rotScaled, + drive.heading + ) + } else { + ChassisSpeeds( + vel.x, + vel.y, + rotScaled + ) + } + } + + override fun initSendable(builder: SendableBuilder) { + builder.addDoubleProperty("currX", this.xThrottle::getAsDouble, null) + builder.addDoubleProperty("currY", this.yThrottle::getAsDouble, null) + builder.addDoubleProperty("prevX", { this.prevX }, null) + builder.addDoubleProperty("prevY", { this.prevY }, null) + builder.addDoubleProperty("dx", { this.dx }, null) + builder.addDoubleProperty("dy", { this.dy }, null) + builder.addDoubleProperty("dt", { this.dt }, null) + builder.addDoubleProperty("magAcc", { this.magAcc }, null) + builder.addDoubleProperty("magAccClamped", { this.magAccClamped }, null) + builder.addStringProperty("speeds", { this.get().toString() }, null) + } + + companion object { + fun createHolonomicOI(drive: HolonomicDrive, driveController: XboxController): HolonomicOI { + return HolonomicOI( + drive, + { if (abs(driveController.leftY) < RobotConstants.TRANSLATION_DEADBAND) .0 else -driveController.leftY }, + { if (abs(driveController.leftX) < RobotConstants.TRANSLATION_DEADBAND) .0 else -driveController.leftX }, + { if (abs(driveController.getRawAxis(4)) < RobotConstants.ROTATION_DEADBAND) .0 else -driveController.getRawAxis(4) }, + SlewRateLimiter(RobotConstants.ROT_RATE_LIMIT, RobotConstants.NEG_ROT_RATE_LIM, 0.0), + RobotConstants.MAX_ACCEL, + { true } + ) + } + } +} diff --git a/src/main/kotlin/frc/team449/control/holonomic/MecanumDrive.kt b/src/main/kotlin/frc/team449/control/holonomic/MecanumDrive.kt new file mode 100644 index 0000000..ea35e7c --- /dev/null +++ b/src/main/kotlin/frc/team449/control/holonomic/MecanumDrive.kt @@ -0,0 +1,204 @@ +package frc.team449.control.holonomic + +import edu.wpi.first.math.MatBuilder +import edu.wpi.first.math.Nat +import edu.wpi.first.math.controller.PIDController +import edu.wpi.first.math.controller.SimpleMotorFeedforward +import edu.wpi.first.math.estimator.MecanumDrivePoseEstimator +import edu.wpi.first.math.geometry.Pose2d +import edu.wpi.first.math.geometry.Translation2d +import edu.wpi.first.math.kinematics.ChassisSpeeds +import edu.wpi.first.math.kinematics.MecanumDriveKinematics +import edu.wpi.first.math.kinematics.MecanumDriveWheelPositions +import edu.wpi.first.math.kinematics.MecanumDriveWheelSpeeds +import edu.wpi.first.wpilibj.Timer +import edu.wpi.first.wpilibj2.command.SubsystemBase +import frc.team449.control.vision.VisionSubsystem +import frc.team449.robot2023.constants.RobotConstants +import frc.team449.robot2023.constants.drives.MecanumConstants +import frc.team449.robot2023.constants.vision.VisionConstants +import frc.team449.system.AHRS +import frc.team449.system.encoder.NEOEncoder +import frc.team449.system.motor.WrappedMotor +import frc.team449.system.motor.createSparkMax + +/** + * @param frontLeftMotor the front left motor + * @param frontRightMotor the front right motor + * @param backLeftMotor the back left motor + * @param backRightMotor the back right motor + * @param frontLeftLocation the offset of the front left wheel to the center of the robot + * @param frontRightLocation the offset of the front right wheel to the center of the robot + * @param backLeftLocation the offset of the back left wheel to the center of the robot + * @param backRightLocation the offset of the back right wheel to the center of the robot + * @param maxLinearSpeed the maximum translation speed of the chassis. + * @param maxRotSpeed the maximum rotation speed of the chassis + * @param feedForward the SimpleMotorFeedforward for mecanum + * @param controller the PIDController for the robot + */ +open class MecanumDrive( + private val frontLeftMotor: WrappedMotor, + private val frontRightMotor: WrappedMotor, + private val backLeftMotor: WrappedMotor, + private val backRightMotor: WrappedMotor, + frontLeftLocation: Translation2d, + frontRightLocation: Translation2d, + backLeftLocation: Translation2d, + backRightLocation: Translation2d, + private val ahrs: AHRS, + override var maxLinearSpeed: Double, + override var maxRotSpeed: Double, + private val feedForward: SimpleMotorFeedforward, + private val controller: () -> PIDController, + private val cameras: List = mutableListOf() +) : HolonomicDrive, SubsystemBase() { + + private val flController = controller() + private val frController = controller() + private val blController = controller() + private val brController = controller() + + private var lastTime = Timer.getFPGATimestamp() + + val kinematics = MecanumDriveKinematics( + frontLeftLocation, + frontRightLocation, + backLeftLocation, + backRightLocation + ) + + private val poseEstimator = MecanumDrivePoseEstimator( + kinematics, + ahrs.heading, + getPositions(), + RobotConstants.INITIAL_POSE, + MatBuilder(Nat.N3(), Nat.N1()).fill(.005, .005, .0005), // [x, y, theta] other estimates + MatBuilder(Nat.N3(), Nat.N1()).fill(.005, .005, .0005) // [x, y, theta] vision estimates + ) + + override var pose: Pose2d + get() { + return this.poseEstimator.estimatedPosition + } + set(value) { + this.poseEstimator.resetPosition(ahrs.heading, getPositions(), value) + } + + private var desiredWheelSpeeds = MecanumDriveWheelSpeeds() + + override fun set(desiredSpeeds: ChassisSpeeds) { + desiredWheelSpeeds = kinematics.toWheelSpeeds(desiredSpeeds) + desiredWheelSpeeds.desaturate(MecanumConstants.MAX_ATTAINABLE_WHEEL_SPEED) + } + + override fun stop() { + this.set(ChassisSpeeds(0.0, 0.0, 0.0)) + } + + override fun periodic() { + val currTime = Timer.getFPGATimestamp() + + val frontLeftPID = flController.calculate(frontLeftMotor.velocity, desiredWheelSpeeds.frontLeftMetersPerSecond) + val frontRightPID = frController.calculate(frontRightMotor.velocity, desiredWheelSpeeds.frontRightMetersPerSecond) + val backLeftPID = blController.calculate(backLeftMotor.velocity, desiredWheelSpeeds.rearLeftMetersPerSecond) + val backRightPID = brController.calculate(backRightMotor.velocity, desiredWheelSpeeds.rearRightMetersPerSecond) + + val frontLeftFF = feedForward.calculate( + desiredWheelSpeeds.frontLeftMetersPerSecond + ) + val frontRightFF = feedForward.calculate( + desiredWheelSpeeds.frontRightMetersPerSecond + ) + val backLeftFF = feedForward.calculate( + desiredWheelSpeeds.rearLeftMetersPerSecond + ) + val backRightFF = feedForward.calculate( + desiredWheelSpeeds.rearRightMetersPerSecond + ) + + frontLeftMotor.setVoltage(frontLeftPID + frontLeftFF) + frontRightMotor.setVoltage(frontRightPID + frontRightFF) + backLeftMotor.setVoltage(backLeftPID + backLeftFF) + backRightMotor.setVoltage(backRightPID + backRightFF) + + if (cameras.isNotEmpty()) localize() + + this.poseEstimator.update( + ahrs.heading, + getPositions() + ) + + lastTime = currTime + } + + /** + * @return the position readings of the wheels bundled into one object (meters) + */ + private fun getPositions(): MecanumDriveWheelPositions = + MecanumDriveWheelPositions( + frontLeftMotor.position, + frontRightMotor.position, + backLeftMotor.position, + backRightMotor.position + ) + + /** + * @return the velocity readings of the wheels bundled into one object (meters/s) + */ + private fun getSpeeds(): MecanumDriveWheelSpeeds = + MecanumDriveWheelSpeeds( + frontLeftMotor.velocity, + frontRightMotor.velocity, + backLeftMotor.velocity, + backRightMotor.velocity + ) + + private fun localize() { + for (camera in cameras) { + val result = camera.estimatedPose(Pose2d(pose.x, pose.y, ahrs.heading)) + if (result.isPresent) { + poseEstimator.addVisionMeasurement( + result.get().estimatedPose.toPose2d(), + result.get().timestampSeconds + ) + } + } + } + + companion object { + + /** Helper method to create a motor for each wheel */ + private fun createCorner(name: String, motorID: Int, inverted: Boolean): WrappedMotor { + return createSparkMax( + name, + motorID, + NEOEncoder.creator( + MecanumConstants.DRIVE_UPR, + MecanumConstants.DRIVE_GEARING + ), + inverted = inverted, + currentLimit = MecanumConstants.CURRENT_LIM + ) + } + + /** Create a new Mecanum Drive from DriveConstants */ + fun createMecanum(ahrs: AHRS): MecanumDrive { + return MecanumDrive( + createCorner("frontLeft", MecanumConstants.DRIVE_MOTOR_FL, false), + createCorner("frontRight", MecanumConstants.DRIVE_MOTOR_FR, true), + createCorner("backLeft", MecanumConstants.DRIVE_MOTOR_BL, false), + createCorner("backRight", MecanumConstants.DRIVE_MOTOR_BR, true), + Translation2d(MecanumConstants.WHEELBASE / 2, MecanumConstants.TRACKWIDTH / 2), + Translation2d(MecanumConstants.WHEELBASE / 2, -MecanumConstants.TRACKWIDTH / 2), + Translation2d(-MecanumConstants.WHEELBASE / 2, MecanumConstants.TRACKWIDTH / 2), + Translation2d(-MecanumConstants.WHEELBASE / 2, -MecanumConstants.TRACKWIDTH / 2), + ahrs, + RobotConstants.MAX_LINEAR_SPEED, + RobotConstants.MAX_ROT_SPEED, + SimpleMotorFeedforward(MecanumConstants.DRIVE_KS, MecanumConstants.DRIVE_KV, MecanumConstants.DRIVE_KA), + { PIDController(MecanumConstants.DRIVE_KP, MecanumConstants.DRIVE_KI, MecanumConstants.DRIVE_KD) }, + VisionConstants.ESTIMATORS + ) + } + } +} diff --git a/src/main/kotlin/frc/team449/control/holonomic/SwerveDrive.kt b/src/main/kotlin/frc/team449/control/holonomic/SwerveDrive.kt new file mode 100644 index 0000000..0ea3208 --- /dev/null +++ b/src/main/kotlin/frc/team449/control/holonomic/SwerveDrive.kt @@ -0,0 +1,482 @@ +package frc.team449.control.holonomic + +import edu.wpi.first.math.MathUtil +import edu.wpi.first.math.controller.PIDController +import edu.wpi.first.math.controller.SimpleMotorFeedforward +import edu.wpi.first.math.estimator.SwerveDrivePoseEstimator +import edu.wpi.first.math.geometry.Pose2d +import edu.wpi.first.math.geometry.Rotation2d +import edu.wpi.first.math.geometry.Transform2d +import edu.wpi.first.math.geometry.Translation2d +import edu.wpi.first.math.kinematics.ChassisSpeeds +import edu.wpi.first.math.kinematics.SwerveDriveKinematics +import edu.wpi.first.math.kinematics.SwerveModulePosition +import edu.wpi.first.math.kinematics.SwerveModuleState +import edu.wpi.first.util.sendable.SendableBuilder +import edu.wpi.first.wpilibj.DriverStation +import edu.wpi.first.wpilibj.RobotBase.isReal +import edu.wpi.first.wpilibj.smartdashboard.Field2d +import edu.wpi.first.wpilibj2.command.SubsystemBase +import frc.team449.control.vision.VisionSubsystem +import frc.team449.robot2023.constants.RobotConstants +import frc.team449.robot2023.constants.drives.SwerveConstants +import frc.team449.robot2023.constants.vision.VisionConstants +import frc.team449.system.AHRS +import frc.team449.system.encoder.AbsoluteEncoder +import frc.team449.system.encoder.NEOEncoder +import frc.team449.system.motor.createSparkMax +import kotlin.math.* + +/** + * A Swerve Drive chassis. + * @param modules An array of [SwerveModule]s that are on the drivetrain. + * @param ahrs The gyro that is mounted on the chassis. + * @param maxLinearSpeed The maximum translation speed of the chassis. + * @param maxRotSpeed The maximum rotation speed of the chassis. + * @param cameras The cameras that help estimate the robot's pose. + * @param field The SmartDashboard [Field2d] widget that shows the robot's pose. + */ +open class SwerveDrive( + protected val modules: List, + protected val ahrs: AHRS, + override var maxLinearSpeed: Double, + override var maxRotSpeed: Double, + protected val cameras: List = mutableListOf(), + protected val field: Field2d +) : SubsystemBase(), HolonomicDrive { + + /** Vision statistics */ + protected var numTargets = DoubleArray(cameras.size) + protected var tagDistance = DoubleArray(cameras.size) + protected var avgAmbiguity = DoubleArray(cameras.size) + protected var heightError = DoubleArray(cameras.size) + protected var usedVision = BooleanArray(cameras.size) + + /** The kinematics that convert [ChassisSpeeds] into multiple [SwerveModuleState] objects. */ + protected val kinematics = SwerveDriveKinematics( + *this.modules.map { it.location }.toTypedArray() + ) + + /** The current speed of the robot's drive. */ + var currentSpeeds = ChassisSpeeds() + + /** Current estimated vision pose */ + var visionPose = Pose2d() + + /** Pose estimator that estimates the robot's position as a [Pose2d]. */ + protected val poseEstimator = SwerveDrivePoseEstimator( + kinematics, + ahrs.heading, + getPositions(), + RobotConstants.INITIAL_POSE, + VisionConstants.ENCODER_TRUST, + VisionConstants.MULTI_TAG_TRUST + ) + + var desiredSpeeds: ChassisSpeeds = ChassisSpeeds() + + protected var maxSpeed: Double = 0.0 + + override fun set(desiredSpeeds: ChassisSpeeds) { + this.desiredSpeeds = desiredSpeeds + + // Converts the desired [ChassisSpeeds] into an array of [SwerveModuleState]. + val desiredModuleStates = + this.kinematics.toSwerveModuleStates(this.desiredSpeeds) + + // Scale down module speed if a module is going faster than the max speed, and prevent early desaturation. + normalizeDrive(desiredModuleStates, desiredSpeeds) +// SwerveDriveKinematics.desaturateWheelSpeeds( +// desiredModuleStates, +// SwerveConstants.MAX_ATTAINABLE_MK4I_SPEED +// ) + + for (i in this.modules.indices) { + this.modules[i].state = desiredModuleStates[i] + } + + for (module in modules) + module.update() + } + + // TODO: Do you notice a difference with this normalize function? + private fun normalizeDrive(desiredStates: Array, speeds: ChassisSpeeds) { + val translationalK: Double = hypot(speeds.vxMetersPerSecond, speeds.vyMetersPerSecond) / RobotConstants.MAX_LINEAR_SPEED + val rotationalK: Double = abs(speeds.omegaRadiansPerSecond) / RobotConstants.MAX_ROT_SPEED + val k = max(translationalK, rotationalK) + + // Find how fast the fastest spinning drive motor is spinning + var realMaxSpeed = 0.0 + for (moduleState in desiredStates) { + realMaxSpeed = max(realMaxSpeed, abs(moduleState.speedMetersPerSecond)) + } + + val scale = + if (realMaxSpeed > 0 && k < 1) + k * SwerveConstants.MAX_ATTAINABLE_MK4I_SPEED / realMaxSpeed + else if (realMaxSpeed > 0) + SwerveConstants.MAX_ATTAINABLE_MK4I_SPEED / realMaxSpeed + else + 1.0 + + for (moduleState in desiredStates) { + moduleState.speedMetersPerSecond *= scale + } + } + + fun setVoltage(volts: Double) { + modules.forEach { + it.setVoltage(volts) + } + } + + fun getModuleVel(): Double { + var totalVel = 0.0 + modules.forEach { totalVel += it.state.speedMetersPerSecond } + return totalVel / modules.size + } + + /** The measured pitch of the robot from the gyro sensor. */ + val pitch: Rotation2d + get() = Rotation2d(MathUtil.angleModulus(ahrs.pitch.radians)) + + /** The measured roll of the robot from the gyro sensor. */ + val roll: Rotation2d + get() = Rotation2d(MathUtil.angleModulus(ahrs.roll.radians)) + + /** The (x, y, theta) position of the robot on the field. */ + override var pose: Pose2d + get() = this.poseEstimator.estimatedPosition + set(value) { + this.poseEstimator.resetPosition( + ahrs.heading, + getPositions(), + value + ) + } + + override fun periodic() { + // Updates the robot's currentSpeeds. + currentSpeeds = kinematics.toChassisSpeeds( + modules[0].state, + modules[1].state, + modules[2].state, + modules[3].state + ) + + val transVel = hypot(currentSpeeds.vxMetersPerSecond, currentSpeeds.vyMetersPerSecond) + if (transVel > maxSpeed) maxSpeed = transVel + + // Update the robot's pose using the gyro heading and the SwerveModulePositions of each module. + this.poseEstimator.update( + ahrs.heading, + getPositions() + ) + + if (cameras.isNotEmpty()) localize() + + // Sets the robot's pose and individual module rotations on the SmartDashboard [Field2d] widget. + setRobotPose() + } + + /** Stops the robot's drive. */ + override fun stop() { + this.set(ChassisSpeeds(0.0, 0.0, 0.0)) + } + + /** @return An array of [SwerveModulePosition] for each module, containing distance and angle. */ + protected fun getPositions(): Array { + return Array(modules.size) { i -> modules[i].position } + } + + /** @return An array of [SwerveModuleState] for each module, containing speed and angle. */ + private fun getStates(): Array { + return Array(modules.size) { i -> modules[i].state } + } + + protected fun setRobotPose() { + this.field.robotPose = this.pose + this.field.getObject("FL").pose = this.pose.plus(Transform2d(Translation2d(SwerveConstants.WHEELBASE / 2, SwerveConstants.TRACKWIDTH / 2), this.getPositions()[0].angle)) + this.field.getObject("FR").pose = this.pose.plus(Transform2d(Translation2d(SwerveConstants.WHEELBASE / 2, -SwerveConstants.TRACKWIDTH / 2), this.getPositions()[1].angle)) + this.field.getObject("BL").pose = this.pose.plus(Transform2d(Translation2d(-SwerveConstants.WHEELBASE / 2, SwerveConstants.TRACKWIDTH / 2), this.getPositions()[2].angle)) + this.field.getObject("BR").pose = this.pose.plus(Transform2d(Translation2d(-SwerveConstants.WHEELBASE / 2, -SwerveConstants.TRACKWIDTH / 2), this.getPositions()[0].angle)) + } + + protected open fun localize() = try { + for ((index, camera) in cameras.withIndex()) { + val result = camera.estimatedPose(Pose2d(pose.x, pose.y, ahrs.heading)) + if (result.isPresent) { + val presentResult = result.get() + numTargets[index] = presentResult.targetsUsed.size.toDouble() + tagDistance[index] = 0.0 + avgAmbiguity[index] = 0.0 + heightError[index] = abs(presentResult.estimatedPose.z - camera.robotToCam.z) + + for (tag in presentResult.targetsUsed) { + val tagPose = camera.estimator.fieldTags.getTagPose(tag.fiducialId) + if (tagPose.isPresent) { + val estimatedToTag = presentResult.estimatedPose.minus(tagPose.get()) + tagDistance[index] += sqrt(estimatedToTag.x.pow(2) + estimatedToTag.y.pow(2)) / numTargets[index] + avgAmbiguity[index] = tag.poseAmbiguity / numTargets[index] + } else { + tagDistance[index] = Double.MAX_VALUE + avgAmbiguity[index] = Double.MAX_VALUE + break + } + } + + visionPose = presentResult.estimatedPose.toPose2d() + + if (presentResult.timestampSeconds > 0 && + avgAmbiguity[index] <= VisionConstants.MAX_AMBIGUITY && + numTargets[index] < 2 && tagDistance[index] <= VisionConstants.MAX_DISTANCE_SINGLE_TAG || + numTargets[index] >= 2 && tagDistance[index] <= VisionConstants.MAX_DISTANCE_MULTI_TAG * (1 + (numTargets[index] - 2) * VisionConstants.TAG_MULTIPLIER) && + heightError[index] < VisionConstants.MAX_HEIGHT_ERR_METERS + ) { + poseEstimator.addVisionMeasurement( + visionPose, + presentResult.timestampSeconds, + camera.getEstimationStdDevs(numTargets[index].toInt(), tagDistance[index]) + ) + usedVision[index] = true + } else { + usedVision[index] = false + } + } + } + } catch (e: Error) { + DriverStation.reportError( + "!!!!!!!!! VISION ERROR !!!!!!!", + e.stackTrace + ) + } + + override fun initSendable(builder: SendableBuilder) { + builder.publishConstString("1.0", "Poses and ChassisSpeeds") + builder.addDoubleArrayProperty("1.1 Estimated Pose", { doubleArrayOf(pose.x, pose.y, pose.rotation.radians) }, null) + builder.addDoubleArrayProperty("1.2 Vision Pose", { doubleArrayOf(visionPose.x, visionPose.y, visionPose.rotation.radians) }, null) + builder.addDoubleArrayProperty("1.3 Current Chassis Speeds", { doubleArrayOf(currentSpeeds.vxMetersPerSecond, currentSpeeds.vyMetersPerSecond, currentSpeeds.omegaRadiansPerSecond) }, null) + builder.addDoubleArrayProperty("1.4 Desired Chassis Speeds", { doubleArrayOf(desiredSpeeds.vxMetersPerSecond, desiredSpeeds.vyMetersPerSecond, desiredSpeeds.omegaRadiansPerSecond) }, null) + builder.addDoubleProperty("1.5 Max Recorded Speed", { maxSpeed }, null) + + builder.publishConstString("2.0", "Vision Stats") + builder.addBooleanArrayProperty("2.1 Used Last Vision Estimate?", { usedVision }, null) + builder.addDoubleArrayProperty("2.2 Number of Targets", { numTargets }, null) + builder.addDoubleArrayProperty("2.3 Avg Tag Distance", { tagDistance }, null) + builder.addDoubleArrayProperty("2.4 Average Ambiguity", { avgAmbiguity }, null) + builder.addDoubleArrayProperty("2.5 Cam Height Error", { heightError }, null) + + builder.publishConstString("3.0", "Steering Rot (Std Order FL, FR, BL, BR)") + builder.addDoubleArrayProperty( + "3.1 Current Rotation", + { DoubleArray(modules.size) { index -> modules[index].position.angle.rotations } }, + null + ) + builder.addDoubleArrayProperty( + "3.2 Desired Rotation", + { DoubleArray(modules.size) { index -> modules[index].desiredState.angle.rotations } }, + null + ) + + builder.publishConstString("4.0", "Module Driving Speeds (Std Order FL, FR, BL, BR)") + builder.addDoubleArrayProperty( + "4.1 Desired Speed", + { DoubleArray(modules.size) { index -> modules[index].desiredState.speedMetersPerSecond } }, + null + ) + builder.addDoubleArrayProperty( + "4.2 Current Speeds", + { DoubleArray(modules.size) { index -> modules[index].state.speedMetersPerSecond } }, + null + ) + + builder.publishConstString("5.0", "Last Module Voltages (Standard Order, FL, FR, BL, BR)") + builder.addDoubleArrayProperty( + "5.1 Driving", + { DoubleArray(modules.size) { index -> modules[index].lastDrivingVoltage() } }, + null + ) + builder.addDoubleArrayProperty( + "5.2 Steering", + { DoubleArray(modules.size) { index -> modules[index].lastSteeringVoltage() } }, + null + ) + + builder.publishConstString("6.0", "AHRS Values") + builder.addDoubleProperty("6.1 Heading Degrees", { ahrs.heading.degrees }, null) + builder.addDoubleProperty("6.2 Pitch Degrees", { ahrs.pitch.degrees }, null) + builder.addDoubleProperty("6.3 Roll Degrees", { ahrs.roll.degrees }, null) + builder.addDoubleProperty("6.4 Angular X Vel", { ahrs.angularXVel() }, null) + + // Note: You should also tune UPR too + builder.publishConstString("7.0", "Tuning Values") + builder.addDoubleProperty("7.1 FL Drive P", { modules[0].driveController.p }, { value -> modules[0].driveController.p = value }) + builder.addDoubleProperty("7.2 FL Drive D", { modules[0].driveController.d }, { value -> modules[0].driveController.d = value }) + builder.addDoubleProperty("7.3 FL Turn P", { modules[0].turnController.p }, { value -> modules[0].turnController.p = value }) + builder.addDoubleProperty("7.4 FL Turn D", { modules[0].turnController.d }, { value -> modules[0].turnController.d = value }) + builder.addDoubleProperty("7.5 FR Drive P", { modules[1].driveController.p }, { value -> modules[1].driveController.p = value }) + builder.addDoubleProperty("7.6 FR Drive D", { modules[1].driveController.d }, { value -> modules[1].driveController.d = value }) + builder.addDoubleProperty("7.8 FR Turn P", { modules[1].turnController.p }, { value -> modules[1].turnController.p = value }) + builder.addDoubleProperty("7.9 FR Turn D", { modules[1].turnController.d }, { value -> modules[1].turnController.d = value }) + builder.addDoubleProperty("7.10 BL Drive P", { modules[2].driveController.p }, { value -> modules[2].driveController.p = value }) + builder.addDoubleProperty("7.11 BL Drive D", { modules[2].driveController.d }, { value -> modules[2].driveController.d = value }) + builder.addDoubleProperty("7.12 BL Turn P", { modules[2].turnController.p }, { value -> modules[2].turnController.p = value }) + builder.addDoubleProperty("7.13 BL Turn D", { modules[2].turnController.d }, { value -> modules[2].turnController.d = value }) + builder.addDoubleProperty("7.14 BR Drive P", { modules[3].driveController.p }, { value -> modules[3].driveController.p = value }) + builder.addDoubleProperty("7.15 BR Drive D", { modules[3].driveController.d }, { value -> modules[3].driveController.d = value }) + builder.addDoubleProperty("7.16 BR Turn P", { modules[3].turnController.p }, { value -> modules[3].turnController.p = value }) + builder.addDoubleProperty("7.17 BR Turn D", { modules[3].turnController.d }, { value -> modules[3].turnController.d = value }) + } + + companion object { + /** Create a [SwerveDrive] using [SwerveConstants]. */ + fun createSwerve(ahrs: AHRS, field: Field2d): SwerveDrive { + val driveMotorController = { PIDController(SwerveConstants.DRIVE_KP, SwerveConstants.DRIVE_KI, SwerveConstants.DRIVE_KD) } + val turnMotorController = { PIDController(SwerveConstants.TURN_KP, SwerveConstants.TURN_KI, SwerveConstants.TURN_KD) } + val driveFeedforward = SimpleMotorFeedforward(SwerveConstants.DRIVE_KS, SwerveConstants.DRIVE_KV, SwerveConstants.DRIVE_KA) + val modules = listOf( + SwerveModule.create( + "FLModule", + makeDrivingMotor( + "FL", + SwerveConstants.DRIVE_MOTOR_FL, + inverted = false + ), + makeTurningMotor( + "FL", + SwerveConstants.TURN_MOTOR_FL, + inverted = true, + sensorPhase = false, + SwerveConstants.TURN_ENC_CHAN_FL, + SwerveConstants.TURN_ENC_OFFSET_FL + ), + driveMotorController(), + turnMotorController(), + driveFeedforward, + Translation2d(SwerveConstants.WHEELBASE / 2, SwerveConstants.TRACKWIDTH / 2) + ), + SwerveModule.create( + "FRModule", + makeDrivingMotor( + "FR", + SwerveConstants.DRIVE_MOTOR_FR, + inverted = false + ), + makeTurningMotor( + "FR", + SwerveConstants.TURN_MOTOR_FR, + inverted = true, + sensorPhase = false, + SwerveConstants.TURN_ENC_CHAN_FR, + SwerveConstants.TURN_ENC_OFFSET_FR + ), + driveMotorController(), + turnMotorController(), + driveFeedforward, + Translation2d(SwerveConstants.WHEELBASE / 2, -SwerveConstants.TRACKWIDTH / 2) + ), + SwerveModule.create( + "BLModule", + makeDrivingMotor( + "BL", + SwerveConstants.DRIVE_MOTOR_BL, + inverted = false + ), + makeTurningMotor( + "BL", + SwerveConstants.TURN_MOTOR_BL, + inverted = true, + sensorPhase = false, + SwerveConstants.TURN_ENC_CHAN_BL, + SwerveConstants.TURN_ENC_OFFSET_BL + ), + driveMotorController(), + turnMotorController(), + driveFeedforward, + Translation2d(-SwerveConstants.WHEELBASE / 2, SwerveConstants.TRACKWIDTH / 2) + ), + SwerveModule.create( + "BRModule", + makeDrivingMotor( + "BR", + SwerveConstants.DRIVE_MOTOR_BR, + inverted = false + ), + makeTurningMotor( + "BR", + SwerveConstants.TURN_MOTOR_BR, + inverted = true, + sensorPhase = false, + SwerveConstants.TURN_ENC_CHAN_BR, + SwerveConstants.TURN_ENC_OFFSET_BR + ), + driveMotorController(), + turnMotorController(), + driveFeedforward, + Translation2d(-SwerveConstants.WHEELBASE / 2, -SwerveConstants.TRACKWIDTH / 2) + ) + ) + return if (isReal()) { + SwerveDrive( + modules, + ahrs, + RobotConstants.MAX_LINEAR_SPEED, + RobotConstants.MAX_ROT_SPEED, + VisionConstants.ESTIMATORS, + field + ) + } else { + SwerveSim( + modules, + ahrs, + RobotConstants.MAX_LINEAR_SPEED, + RobotConstants.MAX_ROT_SPEED, + VisionConstants.ESTIMATORS, + field + ) + } + } + + /** Helper to make turning motors for swerve. */ + private fun makeDrivingMotor( + name: String, + motorId: Int, + inverted: Boolean + ) = + createSparkMax( + name = name + "Drive", + id = motorId, + enableBrakeMode = true, + inverted = inverted, + encCreator = + NEOEncoder.creator( + SwerveConstants.DRIVE_UPR, + SwerveConstants.DRIVE_GEARING + ), + currentLimit = SwerveConstants.DRIVE_CURRENT_LIM + ) + + /** Helper to make turning motors for swerve. */ + private fun makeTurningMotor( + name: String, + motorId: Int, + inverted: Boolean, + sensorPhase: Boolean, + encoderChannel: Int, + offset: Double + ) = + createSparkMax( + name = name + "Turn", + id = motorId, + enableBrakeMode = false, + inverted = inverted, + encCreator = AbsoluteEncoder.creator( + encoderChannel, + offset, + SwerveConstants.TURN_UPR, + sensorPhase + ), + currentLimit = SwerveConstants.STEERING_CURRENT_LIM + ) + } +} diff --git a/src/main/kotlin/frc/team449/control/holonomic/SwerveModule.kt b/src/main/kotlin/frc/team449/control/holonomic/SwerveModule.kt new file mode 100644 index 0000000..82a7578 --- /dev/null +++ b/src/main/kotlin/frc/team449/control/holonomic/SwerveModule.kt @@ -0,0 +1,206 @@ +package frc.team449.control.holonomic + +import edu.wpi.first.math.controller.PIDController +import edu.wpi.first.math.controller.SimpleMotorFeedforward +import edu.wpi.first.math.geometry.Rotation2d +import edu.wpi.first.math.geometry.Translation2d +import edu.wpi.first.math.kinematics.SwerveModulePosition +import edu.wpi.first.math.kinematics.SwerveModuleState +import edu.wpi.first.wpilibj.RobotBase +import edu.wpi.first.wpilibj.Timer +import frc.team449.robot2023.constants.drives.SwerveConstants +import frc.team449.system.encoder.Encoder +import frc.team449.system.motor.WrappedMotor +import kotlin.math.PI +import kotlin.math.abs +import kotlin.math.sign + +/** + * Controls a Swerve Module. + * @param name The name of the module (used for logging). + * @param drivingMotor The motor that controls the speed of the module. + * @param turningMotor The motor that controls the angle of the module + * @param driveController The velocity control for speed of the module + * @param turnController The position control for the angle of the module + * @param driveFeedforward The voltage predicting equation for a given speed of the module. + * @param location The location of the module in reference to the center of the robot. + * NOTE: In relation to the robot [+X is forward, +Y is left, and +THETA is Counter Clock-Wise]. + */ +open class SwerveModule( + private val name: String, + private val drivingMotor: WrappedMotor, + private val turningMotor: WrappedMotor, + val driveController: PIDController, + val turnController: PIDController, + private val driveFeedforward: SimpleMotorFeedforward, + val location: Translation2d +) { + init { + turnController.enableContinuousInput(.0, 2 * PI) + driveController.reset() + turnController.reset() + } + + val desiredState = SwerveModuleState( + 0.0, + Rotation2d() + ) + + /** The module's [SwerveModuleState], containing speed and angle. */ + open var state: SwerveModuleState + get() { + return SwerveModuleState( + drivingMotor.velocity, + Rotation2d(turningMotor.position) + ) + } + set(desState) { + if (abs(desState.speedMetersPerSecond) < .001) { + stop() + return + } + /** Ensure the module doesn't turn more than 90 degrees. */ + val optimizedState = SwerveModuleState.optimize( + desState, + Rotation2d(turningMotor.position) + ) + + turnController.setpoint = optimizedState.angle.radians + driveController.setpoint = optimizedState.speedMetersPerSecond + desiredState.speedMetersPerSecond = optimizedState.speedMetersPerSecond + desiredState.angle = optimizedState.angle + } + + /** The module's [SwerveModulePosition], containing distance and angle. */ + open val position: SwerveModulePosition + get() { + return SwerveModulePosition( + drivingMotor.position, + Rotation2d(turningMotor.position) + ) + } + + fun setVoltage(volts: Double) { + driveController.setpoint = 0.0 + desiredState.speedMetersPerSecond = 0.0 + turnController.setpoint = 0.0 + + turningMotor.setVoltage(turnController.calculate(turningMotor.position)) + drivingMotor.setVoltage(volts) + } + + fun lastDrivingVoltage(): Double { + return drivingMotor.lastVoltage + } + + fun lastSteeringVoltage(): Double { + return turningMotor.lastVoltage + } + + /** Set module speed to zero but keep module angle the same. */ + fun stop() { + turnController.setpoint = turningMotor.position + desiredState.speedMetersPerSecond = 0.0 + } + + open fun update() { + /** CONTROL speed of module */ + val drivePid = driveController.calculate( + drivingMotor.velocity + ) + val driveFF = driveFeedforward.calculate( + desiredState.speedMetersPerSecond + ) + drivingMotor.setVoltage(drivePid + driveFF) + + /** CONTROL direction of module */ + val turnPid = turnController.calculate( + turningMotor.position + ) + + turningMotor.set( + turnPid + + sign(desiredState.angle.radians - turningMotor.position) * + SwerveConstants.STEER_KS + ) + } + + companion object { + /** Create a real or simulated [SwerveModule] based on the simulation status of the robot. */ + fun create( + name: String, + drivingMotor: WrappedMotor, + turningMotor: WrappedMotor, + driveController: PIDController, + turnController: PIDController, + driveFeedforward: SimpleMotorFeedforward, + location: Translation2d + ): SwerveModule { + if (RobotBase.isReal()) { + return SwerveModule( + name, + drivingMotor, + turningMotor, + driveController, + turnController, + driveFeedforward, + location + ) + } else { + return SwerveModuleSim( + name, + drivingMotor, + turningMotor, + driveController, + turnController, + driveFeedforward, + location + ) + } + } + } +} + +/** A "simulated" swerve module. Immediately reaches to its desired state. */ +class SwerveModuleSim( + name: String, + drivingMotor: WrappedMotor, + turningMotor: WrappedMotor, + driveController: PIDController, + turnController: PIDController, + driveFeedforward: SimpleMotorFeedforward, + location: Translation2d +) : SwerveModule( + name, + drivingMotor, + turningMotor, + driveController, + turnController, + driveFeedforward, + location +) { + private val turningMotorEncoder = Encoder.SimController(turningMotor.encoder) + private val driveEncoder = Encoder.SimController(drivingMotor.encoder) + private var prevTime = Timer.getFPGATimestamp() + override var state: SwerveModuleState + get() = SwerveModuleState( + driveEncoder.velocity, + Rotation2d(turningMotorEncoder.position) + ) + set(desiredState) { + super.state = desiredState + turningMotorEncoder.position = desiredState.angle.radians + driveEncoder.velocity = desiredState.speedMetersPerSecond + } + override val position: SwerveModulePosition + get() = SwerveModulePosition( + driveEncoder.position, + Rotation2d(turningMotorEncoder.position) + ) + + override fun update() { + val currTime = Timer.getFPGATimestamp() + driveEncoder.position += driveEncoder.velocity * (currTime - prevTime) + prevTime = currTime + } +} diff --git a/src/main/kotlin/frc/team449/control/holonomic/SwerveOrthogonalCommand.kt b/src/main/kotlin/frc/team449/control/holonomic/SwerveOrthogonalCommand.kt new file mode 100644 index 0000000..dee846d --- /dev/null +++ b/src/main/kotlin/frc/team449/control/holonomic/SwerveOrthogonalCommand.kt @@ -0,0 +1,189 @@ +package frc.team449.control.holonomic + +import edu.wpi.first.math.MathUtil +import edu.wpi.first.math.filter.SlewRateLimiter +import edu.wpi.first.math.geometry.Rotation2d +import edu.wpi.first.math.geometry.Translation2d +import edu.wpi.first.math.kinematics.ChassisSpeeds +import edu.wpi.first.util.sendable.SendableBuilder +import edu.wpi.first.wpilibj.DriverStation +import edu.wpi.first.wpilibj.Timer +import edu.wpi.first.wpilibj.XboxController +import edu.wpi.first.wpilibj2.command.Command +import frc.team449.robot2023.constants.RobotConstants +import frc.team449.robot2023.constants.drives.SwerveConstants +import kotlin.jvm.optionals.getOrNull +import kotlin.math.* + +class SwerveOrthogonalCommand( + private val drive: SwerveDrive, + private val controller: XboxController, + private val fieldOriented: () -> Boolean = { true } +) : Command() { + + private var prevX = 0.0 + private var prevY = 0.0 + + private var prevTime = 0.0 + + private var dx = 0.0 + private var dy = 0.0 + private var magAcc = 0.0 + private var dt = 0.0 + private var magAccClamped = 0.0 + + private var rotScaled = 0.0 + private val allianceCompensation = { if (DriverStation.getAlliance().getOrNull() == DriverStation.Alliance.Red) 0.0 else PI } + private val directionCompensation = { if (DriverStation.getAlliance().getOrNull() == DriverStation.Alliance.Red) -1.0 else 1.0 } + + private var atGoal = true + + private var rotRamp = SlewRateLimiter(RobotConstants.ROT_RATE_LIMIT) + + private val timer = Timer() + + private val rotCtrl = RobotConstants.ORTHOGONAL_CONTROLLER + + private var skewConstant = 11.5 + + private var desiredVel = doubleArrayOf(0.0, 0.0, 0.0) + + init { + addRequirements(drive) + rotCtrl.enableContinuousInput(-PI, PI) + rotCtrl.setTolerance(0.025) + } + + override fun initialize() { + timer.restart() + + prevX = drive.currentSpeeds.vxMetersPerSecond + prevY = drive.currentSpeeds.vyMetersPerSecond + prevTime = 0.0 + dx = 0.0 + dy = 0.0 + magAcc = 0.0 + dt = 0.0 + magAccClamped = 0.0 + + rotRamp = SlewRateLimiter( + RobotConstants.ROT_RATE_LIMIT, + RobotConstants.NEG_ROT_RATE_LIM, + drive.currentSpeeds.omegaRadiansPerSecond + ) + + var atGoal = true + } + + override fun execute() { + val currTime = timer.get() + dt = currTime - prevTime + prevTime = currTime + + val ctrlX = if (abs(controller.leftY) < RobotConstants.TRANSLATION_DEADBAND) .0 else -controller.leftY + val ctrlY = if (abs(controller.leftX) < RobotConstants.TRANSLATION_DEADBAND) .0 else -controller.leftX + + val ctrlRadius = sqrt(ctrlX.pow(2) + ctrlY.pow(2)).pow(SwerveConstants.JOYSTICK_FILTER_ORDER) + + val ctrlTheta = atan2(ctrlY, ctrlX) + + val xScaled = ctrlRadius * cos(ctrlTheta) * RobotConstants.MAX_LINEAR_SPEED + val yScaled = ctrlRadius * sin(ctrlTheta) * RobotConstants.MAX_LINEAR_SPEED + + dx = xScaled - prevX + dy = yScaled - prevY + magAcc = hypot(dx / dt, dy / dt) + magAccClamped = MathUtil.clamp(magAcc, -RobotConstants.MAX_ACCEL, RobotConstants.MAX_ACCEL) + + val factor = if (magAcc == 0.0) 0.0 else magAccClamped / magAcc + val dxClamped = dx * factor + val dyClamped = dy * factor + val xClamped = prevX + dxClamped + val yClamped = prevY + dyClamped + + prevX = xClamped + prevY = yClamped + + if (controller.xButtonPressed) { + val desAngleA = MathUtil.angleModulus(7 * PI / 4 + allianceCompensation.invoke()) + if (abs(desAngleA - drive.heading.radians) > 0.075 && abs(desAngleA - drive.heading.radians) < 2 * PI - 0.075) { + atGoal = false + rotCtrl.setpoint = desAngleA + } + } else if (controller.yButtonPressed) { + val desAngleY = MathUtil.angleModulus(3 * PI / 2 + allianceCompensation.invoke()) + if (abs(desAngleY - drive.heading.radians) > 0.075 && abs(desAngleY - drive.heading.radians) < 2 * PI - 0.075) { + atGoal = false + rotCtrl.setpoint = desAngleY + } + } + + if (atGoal) { + rotScaled = rotRamp.calculate( + (if (abs(controller.rightX) < RobotConstants.ROTATION_DEADBAND) .0 else -controller.rightX) * + drive.maxRotSpeed + ) + } else { + rotScaled = MathUtil.clamp( + rotCtrl.calculate(drive.heading.radians), + -RobotConstants.ALIGN_ROT_SPEED, + RobotConstants.ALIGN_ROT_SPEED + ) + atGoal = rotCtrl.atSetpoint() + } + + val vel = Translation2d(xClamped, yClamped) + + if (fieldOriented.invoke()) { + /** Quick fix for the velocity skewing towards the direction of rotation + * by rotating it with offset proportional to how much we are rotating + **/ + vel.rotateBy(Rotation2d(-rotScaled * dt * skewConstant)) + + val desVel = ChassisSpeeds.fromFieldRelativeSpeeds( + vel.x * directionCompensation.invoke(), + vel.y * directionCompensation.invoke(), + rotScaled, + drive.heading + ) + drive.set( + desVel + ) + + desiredVel[0] = desVel.vxMetersPerSecond + desiredVel[1] = desVel.vyMetersPerSecond + desiredVel[2] = desVel.omegaRadiansPerSecond + } else { + drive.set( + ChassisSpeeds( + vel.x, + vel.y, + rotScaled + ) + ) + } + } + + override fun initSendable(builder: SendableBuilder) { + builder.publishConstString("1.0", "Controller X and Y Values") + builder.addDoubleProperty("1.1 currX", { if (abs(controller.leftY) < RobotConstants.TRANSLATION_DEADBAND) .0 else -controller.leftY }, null) + builder.addDoubleProperty("1.2 currY", { if (abs(controller.leftX) < RobotConstants.TRANSLATION_DEADBAND) .0 else -controller.leftX }, null) + builder.addDoubleProperty("1.3 prevX", { prevX }, null) + builder.addDoubleProperty("1.4 prevY", { prevY }, null) + + builder.publishConstString("2.0", "Delta X, Y, Time over one loop") + builder.addDoubleProperty("2.1 dx", { dx }, null) + builder.addDoubleProperty("2.2 dy", { dy }, null) + builder.addDoubleProperty("2.3 dt", { dt }, null) + + builder.publishConstString("3.0", "Magnitude of Acceleration") + builder.addDoubleProperty("3.1 magAcc", { magAcc }, null) + builder.addDoubleProperty("3.2 magAccClamped", { magAccClamped }, null) + + builder.publishConstString("4.0", "Turning Skew") + builder.addDoubleProperty("4.1 skew constant", { skewConstant }, { k: Double -> skewConstant = k }) + + builder.publishConstString("5.0", "Given Speeds") + builder.addDoubleArrayProperty("Chassis Speed", { desiredVel }, null) + } +} diff --git a/src/main/kotlin/frc/team449/control/holonomic/SwerveSim.kt b/src/main/kotlin/frc/team449/control/holonomic/SwerveSim.kt new file mode 100644 index 0000000..fbee4da --- /dev/null +++ b/src/main/kotlin/frc/team449/control/holonomic/SwerveSim.kt @@ -0,0 +1,139 @@ +package frc.team449.control.holonomic + +import edu.wpi.first.math.geometry.Pose2d +import edu.wpi.first.math.geometry.Rotation2d +import edu.wpi.first.math.kinematics.SwerveDriveOdometry +import edu.wpi.first.wpilibj.DriverStation +import edu.wpi.first.wpilibj.Timer.getFPGATimestamp +import edu.wpi.first.wpilibj.smartdashboard.Field2d +import frc.team449.control.vision.VisionSubsystem +import frc.team449.robot2023.constants.vision.VisionConstants +import frc.team449.system.AHRS +import kotlin.math.abs +import kotlin.math.hypot +import kotlin.math.pow +import kotlin.math.sqrt + +class SwerveSim( + modules: List, + ahrs: AHRS, + maxLinearSpeed: Double, + maxRotSpeed: Double, + cameras: List, + field: Field2d +) : SwerveDrive(modules, ahrs, maxLinearSpeed, maxRotSpeed, cameras, field) { + + private var lastTime = getFPGATimestamp() + var odoPose = Pose2d() + var currHeading = Rotation2d() + + private val odometry = SwerveDriveOdometry( + kinematics, + currHeading, + getPositions() + ) + + /** The (x, y, theta) position of the robot on the field. */ + override var pose: Pose2d + get() = this.poseEstimator.estimatedPosition + set(value) { + this.poseEstimator.resetPosition( + currHeading, + getPositions(), + value + ) + + odometry.resetPosition( + currHeading, + getPositions(), + value + ) + } + + override fun localize() = try { + for ((index, camera) in cameras.withIndex()) { + val result = camera.estimatedPose(Pose2d(pose.x, pose.y, currHeading)) + if (result.isPresent) { + val presentResult = result.get() + numTargets[index] = presentResult.targetsUsed.size.toDouble() + tagDistance[index] = 0.0 + avgAmbiguity[index] = 0.0 + heightError[index] = abs(presentResult.estimatedPose.z) + + for (tag in presentResult.targetsUsed) { + val tagPose = camera.estimator.fieldTags.getTagPose(tag.fiducialId) + if (tagPose.isPresent) { + val estimatedToTag = presentResult.estimatedPose.minus(tagPose.get()) + tagDistance[index] += sqrt(estimatedToTag.x.pow(2) + estimatedToTag.y.pow(2)) / numTargets[index] + avgAmbiguity[index] = tag.poseAmbiguity / numTargets[index] + } else { + tagDistance[index] = Double.MAX_VALUE + avgAmbiguity[index] = Double.MAX_VALUE + break + } + } + + visionPose = presentResult.estimatedPose.toPose2d() + + if (presentResult.timestampSeconds > 0 && + avgAmbiguity[index] <= VisionConstants.MAX_AMBIGUITY && + numTargets[index] < 2 && tagDistance[index] <= VisionConstants.MAX_DISTANCE_SINGLE_TAG || + numTargets[index] >= 2 && tagDistance[index] <= VisionConstants.MAX_DISTANCE_MULTI_TAG * (1 + (numTargets[index] - 2) * VisionConstants.TAG_MULTIPLIER) && + heightError[index] < VisionConstants.MAX_HEIGHT_ERR_METERS + ) { + poseEstimator.addVisionMeasurement( + visionPose, + presentResult.timestampSeconds, + camera.getEstimationStdDevs(numTargets[index].toInt(), tagDistance[index]) + ) + usedVision[index] = true + } else { + usedVision[index] = false + } + } + } + } catch (e: Error) { + DriverStation.reportError( + "!!!!!!!!! VISION ERROR !!!!!!!", + e.stackTrace + ) + } + + override fun periodic() { + val currTime = getFPGATimestamp() + + currHeading = currHeading.plus(Rotation2d(super.desiredSpeeds.omegaRadiansPerSecond * (currTime - lastTime))) + this.lastTime = currTime + + set(super.desiredSpeeds) + + // Updates the robot's currentSpeeds. + currentSpeeds = kinematics.toChassisSpeeds( + modules[0].state, + modules[1].state, + modules[2].state, + modules[3].state + ) + + val transVel = hypot(currentSpeeds.vxMetersPerSecond, currentSpeeds.vyMetersPerSecond) + if (transVel > maxSpeed) maxSpeed = transVel + + // Update the robot's pose using the gyro heading and the SwerveModulePositions of each module. + this.poseEstimator.update( + currHeading, + getPositions() + ) + + if (cameras.isNotEmpty()) localize() + + // Sets the robot's pose and individual module rotations on the SmartDashboard [Field2d] widget. + setRobotPose() + + odoPose = odometry.update( + currHeading, + getPositions() + ) + + field.getObject("odo").pose = odoPose + } +} diff --git a/src/main/kotlin/frc/team449/control/vision/VisionEstimator.kt b/src/main/kotlin/frc/team449/control/vision/VisionEstimator.kt new file mode 100644 index 0000000..8598165 --- /dev/null +++ b/src/main/kotlin/frc/team449/control/vision/VisionEstimator.kt @@ -0,0 +1,303 @@ +package frc.team449.control.vision + +import edu.wpi.first.apriltag.AprilTag +import edu.wpi.first.apriltag.AprilTagFieldLayout +import edu.wpi.first.math.Matrix +import edu.wpi.first.math.geometry.* +import edu.wpi.first.math.numbers.N1 +import edu.wpi.first.math.numbers.N3 +import edu.wpi.first.math.numbers.N5 +import edu.wpi.first.wpilibj.DriverStation +import frc.team449.robot2023.constants.vision.VisionConstants +import org.photonvision.EstimatedRobotPose +import org.photonvision.PhotonCamera +import org.photonvision.PhotonPoseEstimator +import org.photonvision.estimation.OpenCVHelp +import org.photonvision.targeting.PNPResults +import org.photonvision.targeting.PhotonPipelineResult +import org.photonvision.targeting.PhotonTrackedTarget +import org.photonvision.targeting.TargetCorner +import java.util.Optional +import kotlin.math.PI +import kotlin.math.abs + +/** + * This class uses normal multi-tag PNP and lowest ambiguity using the gyro rotation + * for the internal cam-to-tag transform as a fallback strategy + */ +class VisionEstimator( + private val tagLayout: AprilTagFieldLayout, + val camera: PhotonCamera, + private val robotToCam: Transform3d +) : PhotonPoseEstimator(tagLayout, PoseStrategy.MULTI_TAG_PNP_ON_RIO, camera, robotToCam) { + private val reportedErrors: HashSet = HashSet() + private var driveHeading: Rotation2d? = null + private var lastPose: Pose3d? = null + + fun estimatedPose(currPose: Pose2d): Optional { + driveHeading = currPose.rotation + lastPose = Pose3d(currPose.x, currPose.y, 0.0, Rotation3d(0.0, 0.0, currPose.rotation.radians)) + return updatePose(camera.latestResult) + } + + private fun updatePose(cameraResult: PhotonPipelineResult?): Optional { + // Time in the past -- give up, since the following if expects times > 0 + if (cameraResult!!.timestampSeconds < 0) { + return Optional.empty() + } + + // If the pose cache timestamp was set, and the result is from the same timestamp, return an + // empty result + if (poseCacheTimestampSeconds > 0 && + abs(poseCacheTimestampSeconds - cameraResult.timestampSeconds) < 1e-6 + ) { + return Optional.empty() + } + + // Remember the timestamp of the current result used + poseCacheTimestampSeconds = cameraResult.timestampSeconds + + // If no targets seen, trivial case -- return empty result + return if (!cameraResult.hasTargets()) { + Optional.empty() + } else { + multiTagPNPStrategy(cameraResult) + } + } + + private fun checkBest(check: Pose3d?, opt1: Pose3d?, opt2: Pose3d?): Pose3d? { + if (check == null || opt1 == null || opt2 == null) return null + val dist1 = check.translation.toTranslation2d().getDistance(opt1.translation.toTranslation2d()) + val dist2 = check.translation.toTranslation2d().getDistance(opt2.translation.toTranslation2d()) + + return if (dist1 < dist2) { + opt1 + } else { + opt2 + } + } + + private fun multiTagPNPStrategy(result: PhotonPipelineResult): Optional { + // Arrays we need declared up front + val visCorners = ArrayList() + val knownVisTags = ArrayList() + val fieldToCams = ArrayList() + val fieldToCamsAlt = ArrayList() + val usedTargets = ArrayList() + if (result.getTargets().size < 2) { + // Run fallback strategy instead + return lowestAmbiguityStrategy(result) + } + for (target: PhotonTrackedTarget in result.getTargets()) { + val tagPoseOpt = tagLayout.getTagPose(target.fiducialId) + if (tagPoseOpt.isEmpty) { + reportFiducialPoseError(target.fiducialId) + continue + } + val tagPose = tagPoseOpt.get() + + usedTargets.add(target) + + visCorners.addAll(target.detectedCorners) + // actual layout poses of visible tags -- not exposed, so have to recreate + knownVisTags.add(AprilTag(target.fiducialId, tagPose)) + fieldToCams.add(tagPose.transformBy(target.bestCameraToTarget.inverse())) + fieldToCamsAlt.add(tagPose.transformBy(target.alternateCameraToTarget.inverse())) + } + val cameraMatrixOpt = camera.cameraMatrix + val distCoeffsOpt = camera.distCoeffs + val hasCalibData = cameraMatrixOpt.isPresent && distCoeffsOpt.isPresent + + // multi-target solvePNP + if (hasCalibData && visCorners.size == knownVisTags.size * 4 && knownVisTags.isNotEmpty()) { + val cameraMatrix = cameraMatrixOpt.get() + val distCoeffs = distCoeffsOpt.get() + val pnpResults = estimateCamPosePNP(cameraMatrix, distCoeffs, usedTargets.toList()) + val best = Pose3d() + .plus(pnpResults.best) // field-to-camera + .plus(robotToCam.inverse()) // field-to-robot + + val alternate = Pose3d() + .plus(pnpResults.alt) + .plus(robotToCam.inverse()) + + return Optional.of( + EstimatedRobotPose( + checkBest(lastPose, best, alternate) ?: best, + result.timestampSeconds, + result.targets, + PoseStrategy.MULTI_TAG_PNP_ON_RIO + ) + ) + } + + return Optional.empty() + } + + /** + * Return the estimated position of the robot with the lowest position ambiguity from a List of + * pipeline results. + * + * @param result pipeline result + * @return the estimated position of the robot in the FCS and the estimated timestamp of this + * estimation. + */ + private fun lowestAmbiguityStrategy(result: PhotonPipelineResult): Optional { + var lowestAmbiguityTarget: PhotonTrackedTarget? = null + var lowestAmbiguityScore = 10.0 + for (target: PhotonTrackedTarget in result.targets) { + val targetPoseAmbiguity = target.poseAmbiguity + // Make sure the target is a Fiducial target. + if (targetPoseAmbiguity != -1.0 && targetPoseAmbiguity < lowestAmbiguityScore) { + lowestAmbiguityScore = targetPoseAmbiguity + lowestAmbiguityTarget = target + } + } + + // Although there are confirmed to be targets, none of them may be fiducial + // targets. + if (lowestAmbiguityTarget == null) return Optional.empty() + val targetFiducialId = lowestAmbiguityTarget.fiducialId + val targetPosition = tagLayout.getTagPose(targetFiducialId) + if (targetPosition.isEmpty) { + reportFiducialPoseError(targetFiducialId) + return Optional.empty() + } + + val bestPose = targetPosition + .get() + .transformBy( + Transform3d( + lowestAmbiguityTarget.bestCameraToTarget.translation, + Rotation3d( + lowestAmbiguityTarget.bestCameraToTarget.rotation.x, + lowestAmbiguityTarget.bestCameraToTarget.rotation.y, + driveHeading!!.radians + robotToCam.rotation.z - targetPosition.get().rotation.z + ) + ).inverse() + ) + .transformBy(robotToCam.inverse()) + + val altPose = targetPosition + .get() + .transformBy( + Transform3d( + lowestAmbiguityTarget.alternateCameraToTarget.translation, + Rotation3d( + lowestAmbiguityTarget.alternateCameraToTarget.rotation.x, + lowestAmbiguityTarget.alternateCameraToTarget.rotation.y, + driveHeading!!.radians + robotToCam.rotation.z - targetPosition.get().rotation.z + ) + ).inverse() + ) + .transformBy(robotToCam.inverse()) + + val usedPose = checkBest(lastPose, bestPose, altPose) ?: bestPose + + if (usedPose == bestPose) { + val camBestPose = targetPosition + .get() + .transformBy( + Transform3d( + lowestAmbiguityTarget.bestCameraToTarget.translation, + lowestAmbiguityTarget.bestCameraToTarget.rotation + ).inverse() + ) + .transformBy(robotToCam.inverse()) + + if (abs(camBestPose.rotation.z * (180 / (2 * PI)) - driveHeading!!.degrees) > VisionConstants.SINGLE_TAG_HEADING_MAX_DEV_DEG) { + DriverStation.reportWarning("Best Single Tag Heading over Max Deviation, deviated by ${abs(camBestPose.rotation.z * (180 / (2 * PI)) - driveHeading!!.degrees)}", false) + return Optional.empty() + } + } else { + + val camAltPose = targetPosition + .get() + .transformBy( + Transform3d( + lowestAmbiguityTarget.alternateCameraToTarget.translation, + lowestAmbiguityTarget.alternateCameraToTarget.rotation + ).inverse() + ) + .transformBy(robotToCam.inverse()) + + if (abs(camAltPose.rotation.z * (180 / (2 * PI)) - driveHeading!!.degrees) > VisionConstants.SINGLE_TAG_HEADING_MAX_DEV_DEG) { + DriverStation.reportWarning("Alt Single Tag Heading over Max Deviation, deviated by ${abs(camAltPose.rotation.z * (180 / (2 * PI)) - driveHeading!!.degrees)}", false) + return Optional.empty() + } + } + + return Optional.of( + EstimatedRobotPose( + checkBest(lastPose, bestPose, altPose) ?: bestPose, + result.timestampSeconds, + mutableListOf(lowestAmbiguityTarget), + PoseStrategy.LOWEST_AMBIGUITY + ) + ) + } + + private fun reportFiducialPoseError(fiducialId: Int) { + if (!reportedErrors.contains(fiducialId)) { + DriverStation.reportError( + "[PhotonPoseEstimator] Tried to get pose of unknown AprilTag: $fiducialId", + false + ) + reportedErrors.add(fiducialId) + } + } + + private fun estimateCamPosePNP( + cameraMatrix: Matrix?, + distCoeffs: Matrix?, + visTags: List?, + ): PNPResults { + if (visTags == null || tagLayout.tags.isEmpty() || visTags.isEmpty()) { + return PNPResults() + } + val corners = java.util.ArrayList() + val knownTags = java.util.ArrayList() + // ensure these are AprilTags in our layout + for (tgt in visTags) { + val id = tgt.fiducialId + tagLayout + .getTagPose(id) + .ifPresent { pose: Pose3d? -> + knownTags.add(AprilTag(id, pose)) + corners.addAll(tgt.detectedCorners) + } + } + if (knownTags.size == 0 || corners.size == 0 || corners.size % 4 != 0) { + return PNPResults() + } + val points = OpenCVHelp.cornersToPoints(corners) + + // single-tag pnp + return if (knownTags.size == 1) { + val camToTag = OpenCVHelp.solvePNP_SQUARE(cameraMatrix, distCoeffs, VisionConstants.TAG_MODEL.vertices, points) + if (!camToTag.isPresent) return PNPResults() + val bestPose = knownTags[0].pose.transformBy(camToTag.best.inverse()) + var altPose: Pose3d? = Pose3d() + if (camToTag.ambiguity != 0.0) altPose = knownTags[0].pose.transformBy(camToTag.alt.inverse()) + val o = Pose3d() + PNPResults( + Transform3d(o, bestPose), + Transform3d(o, altPose), + camToTag.ambiguity, + camToTag.bestReprojErr, + camToTag.altReprojErr + ) + } else { + val objectTrls = java.util.ArrayList() + for (tag in knownTags) objectTrls.addAll(VisionConstants.TAG_MODEL.getFieldVertices(tag.pose)) + val camToOrigin = OpenCVHelp.solvePNP_SQPNP(cameraMatrix, distCoeffs, objectTrls, points) + if (!camToOrigin.isPresent) PNPResults() else PNPResults( + camToOrigin.best.inverse(), + camToOrigin.alt.inverse(), + camToOrigin.ambiguity, + camToOrigin.bestReprojErr, + camToOrigin.altReprojErr + ) + } + } +} diff --git a/src/main/kotlin/frc/team449/control/vision/VisionSubsystem.kt b/src/main/kotlin/frc/team449/control/vision/VisionSubsystem.kt new file mode 100644 index 0000000..1681e2d --- /dev/null +++ b/src/main/kotlin/frc/team449/control/vision/VisionSubsystem.kt @@ -0,0 +1,106 @@ +package frc.team449.control.vision + +import edu.wpi.first.apriltag.AprilTagFieldLayout +import edu.wpi.first.math.Matrix +import edu.wpi.first.math.geometry.Pose2d +import edu.wpi.first.math.geometry.Rotation2d +import edu.wpi.first.math.geometry.Transform3d +import edu.wpi.first.math.numbers.N1 +import edu.wpi.first.math.numbers.N3 +import edu.wpi.first.wpilibj.RobotBase +import edu.wpi.first.wpilibj.smartdashboard.Field2d +import frc.team449.robot2023.constants.vision.VisionConstants +import org.photonvision.EstimatedRobotPose +import org.photonvision.PhotonCamera +import org.photonvision.simulation.PhotonCameraSim +import org.photonvision.simulation.SimCameraProperties +import org.photonvision.simulation.VisionSystemSim +import java.util.Optional +import kotlin.math.abs +import kotlin.math.pow + + +class VisionSubsystem( + name: String, + tagLayout: AprilTagFieldLayout, + val robotToCam: Transform3d, + private val visionSystemSim: VisionSystemSim? +) { + val estimator = VisionEstimator( + tagLayout, + PhotonCamera(name), + robotToCam + ) + + private var lastEstTimestamp = 0.0 + + private var cameraSim: PhotonCameraSim? = null + + init { + if (RobotBase.isSimulation()) { + visionSystemSim!!.addAprilTags(tagLayout) + + val cameraProp = SimCameraProperties() + cameraProp.setCalibration(VisionConstants.SIM_CAMERA_WIDTH_PX, VisionConstants.SIM_CAMERA_HEIGHT_PX, Rotation2d.fromDegrees(VisionConstants.SIM_FOV_DEG)) + cameraProp.setCalibError(VisionConstants.SIM_CALIB_AVG_ERR_PX, VisionConstants.SIM_CALIB_ERR_STDDEV_PX) + cameraProp.fps = VisionConstants.SIM_FPS + cameraProp.avgLatencyMs = VisionConstants.SIM_AVG_LATENCY + cameraProp.latencyStdDevMs = VisionConstants.SIM_STDDEV_LATENCY + + cameraSim = PhotonCameraSim(estimator.camera, cameraProp) + + cameraSim!!.enableDrawWireframe(VisionConstants.ENABLE_WIREFRAME) + + visionSystemSim.addCamera(cameraSim, robotToCam) + } + } + + private fun getSimDebugField(): Field2d? { + return if (!RobotBase.isSimulation()) null else visionSystemSim!!.debugField + } + + fun estimatedPose(currPose: Pose2d): Optional { + val visionEst = estimator.estimatedPose(currPose) + val latestTimestamp = estimator.camera.latestResult.timestampSeconds + val newResult = abs(latestTimestamp - lastEstTimestamp) > 1e-4 + if (RobotBase.isSimulation()) { + visionEst.ifPresentOrElse( + { est -> + getSimDebugField()!! + .getObject("VisionEstimation").pose = est.estimatedPose.toPose2d() + } + ) { if (newResult) getSimDebugField()!!.getObject("VisionEstimation").setPoses() } + } + return if (newResult) { + lastEstTimestamp = latestTimestamp + visionEst + } else { + Optional.empty() + } + } + + fun getEstimationStdDevs(numTags: Int, avgDist: Double): Matrix { + var estStdDevs = VisionConstants.SINGLE_TAG_TRUST.copy() + + if (numTags == 0) return estStdDevs + + // Decrease std devs if multiple targets are visible + if (numTags > 1) estStdDevs = VisionConstants.MULTI_TAG_TRUST.copy() + + // Increase std devs based on (average) distance + estStdDevs.times( + 1 + avgDist.pow(VisionConstants.ORDER) * VisionConstants.PROPORTION + ) + + return estStdDevs + } + + fun simulationPeriodic(robotSimPose: Pose2d?) { + visionSystemSim!!.update(robotSimPose) + } + + /** Reset pose history of the robot in the vision system simulation. */ + fun resetSimPose(pose: Pose2d?) { + if (RobotBase.isSimulation()) visionSystemSim!!.resetRobotPose(pose) + } +} \ No newline at end of file diff --git a/src/main/kotlin/frc/team449/robot2023/Robot.kt b/src/main/kotlin/frc/team449/robot2023/Robot.kt new file mode 100644 index 0000000..c53308e --- /dev/null +++ b/src/main/kotlin/frc/team449/robot2023/Robot.kt @@ -0,0 +1,40 @@ +package frc.team449.robot2023 + +import edu.wpi.first.wpilibj.PowerDistribution +import edu.wpi.first.wpilibj.SPI +import edu.wpi.first.wpilibj.XboxController +import frc.team449.RobotBase +import frc.team449.control.holonomic.SwerveDrive +import frc.team449.control.holonomic.SwerveOrthogonalCommand +import frc.team449.robot2023.constants.RobotConstants +import frc.team449.robot2023.subsystems.light.Light +import frc.team449.system.AHRS +import monologue.Logged +import monologue.Monologue.LogBoth + +class Robot : RobotBase(), Logged { + + val driveController = XboxController(0) + + val mechController = XboxController(1) + + val ahrs = AHRS(SPI.Port.kMXP) + + // Instantiate/declare PDP and other stuff here + + @LogBoth + override val powerDistribution: PowerDistribution = PowerDistribution( + RobotConstants.PDH_CAN, + PowerDistribution.ModuleType.kRev + ) + + @LogBoth + override val drive = SwerveDrive.createSwerve(ahrs, field) + + @LogBoth + override val driveCommand = SwerveOrthogonalCommand(drive, driveController) + + val light = Light.createLight() +// +// val infrared = DigitalInput(RobotConstants.IR_CHANNEL) +} diff --git a/src/main/kotlin/frc/team449/robot2023/auto/AutoUtil.kt b/src/main/kotlin/frc/team449/robot2023/auto/AutoUtil.kt new file mode 100644 index 0000000..a32c17c --- /dev/null +++ b/src/main/kotlin/frc/team449/robot2023/auto/AutoUtil.kt @@ -0,0 +1,58 @@ +package frc.team449.robot2023.auto + +import edu.wpi.first.math.MatBuilder +import edu.wpi.first.math.MathUtil +import edu.wpi.first.math.numbers.N2 +import edu.wpi.first.math.numbers.N3 +import frc.team449.control.auto.ChoreoTrajectory +import frc.team449.robot2023.constants.field.FieldConstants +import kotlin.math.PI + +object AutoUtil { + fun transformForPos2(pathGroup: MutableList): MutableList { + for (index in 0 until pathGroup.size) { + for (time in pathGroup[index].objectiveTimestamps) { + val currentMatrix = pathGroup[index].stateMap.get(time) + + val newMatrix = MatBuilder(N2.instance, N3.instance).fill( + currentMatrix[0, 0], + FieldConstants.fieldWidth - currentMatrix[0, 1], + -currentMatrix[0, 2], + currentMatrix[1, 0], + -currentMatrix[1, 1], + -currentMatrix[1, 2] + ) + + pathGroup[index].stateMap.put(time, newMatrix) + } + } + + return pathGroup + } + + fun transformForRed(pathGroup: MutableList): MutableList { + for (index in 0 until pathGroup.size) { + for (time in pathGroup[index].objectiveTimestamps) { + val currentMatrix = pathGroup[index].stateMap.get(time) + + val newMatrix = MatBuilder(N2.instance, N3.instance).fill( + FieldConstants.fieldLength - currentMatrix[0, 0], + FieldConstants.fieldWidth - currentMatrix[0, 1], + MathUtil.angleModulus(PI + currentMatrix[0, 2]), + -currentMatrix[1, 0], + -currentMatrix[1, 1], + currentMatrix[1, 2] + ) + + pathGroup[index].stateMap.put(time, newMatrix) + } + } + + return pathGroup + } + + /** Add other methods that return commands that do groups of actions that are done + * across different auto routines. For Charged UP, these methods were things such as + * dropping a cone/cube, or getting in ground intake position, etc. + */ +} diff --git a/src/main/kotlin/frc/team449/robot2023/auto/routines/DoNothing.kt b/src/main/kotlin/frc/team449/robot2023/auto/routines/DoNothing.kt new file mode 100644 index 0000000..8832f55 --- /dev/null +++ b/src/main/kotlin/frc/team449/robot2023/auto/routines/DoNothing.kt @@ -0,0 +1,24 @@ +package frc.team449.robot2023.auto.routines + +import edu.wpi.first.wpilibj2.command.Command +import edu.wpi.first.wpilibj2.command.InstantCommand +import frc.team449.control.auto.ChoreoRoutine +import frc.team449.control.auto.ChoreoRoutineStructure +import frc.team449.control.auto.ChoreoTrajectory +import frc.team449.robot2023.Robot + +class DoNothing( + robot: Robot +) : ChoreoRoutineStructure { + + override val routine = + ChoreoRoutine( + drive = robot.drive + ) + + override val trajectory: MutableList = mutableListOf() + + override fun createCommand(): Command { + return InstantCommand() + } +} diff --git a/src/main/kotlin/frc/team449/robot2023/auto/routines/RoutineChooser.kt b/src/main/kotlin/frc/team449/robot2023/auto/routines/RoutineChooser.kt new file mode 100644 index 0000000..6f0a047 --- /dev/null +++ b/src/main/kotlin/frc/team449/robot2023/auto/routines/RoutineChooser.kt @@ -0,0 +1,23 @@ +package frc.team449.robot2023.auto.routines + +import edu.wpi.first.wpilibj.smartdashboard.SendableChooser +import edu.wpi.first.wpilibj2.command.Command +import frc.team449.robot2023.Robot + +class RoutineChooser(private val robot: Robot) : SendableChooser() { + + fun routineMap(): HashMap { + return hashMapOf( + "DoNothing" to DoNothing(robot).createCommand(), + ) + } + + init { + updateOptions(true) + } + + fun updateOptions(isRed: Boolean) { + /** Add auto options here */ + this.setDefaultOption("Do Nothing", "DoNothing") + } +} diff --git a/src/main/kotlin/frc/team449/robot2023/commands/characterization/Characterization.kt b/src/main/kotlin/frc/team449/robot2023/commands/characterization/Characterization.kt new file mode 100644 index 0000000..0169ea2 --- /dev/null +++ b/src/main/kotlin/frc/team449/robot2023/commands/characterization/Characterization.kt @@ -0,0 +1,85 @@ +// Copyright (c) 2023 FRC 6328 +// http://github.com/Mechanical-Advantage +// +// Use of this source code is governed by an MIT-style +// license that can be found in the LICENSE file at +// the root directory of this project. +package frc.team449.robot2023.commands.characterization + +import edu.wpi.first.wpilibj.Timer +import edu.wpi.first.wpilibj2.command.Command +import edu.wpi.first.wpilibj2.command.Subsystem +import java.util.LinkedList +import java.util.function.DoubleConsumer +import java.util.function.DoubleSupplier +import kotlin.math.abs + +class Characterization( + subsystem: Subsystem?, + private val forward: Boolean, + private val name: String, + private val voltageConsumer: DoubleConsumer, + private val velocitySupplier: DoubleSupplier +) : Command() { + private val timer = Timer() + private val data = FeedForwardCharacterizationData(name) + + init { + addRequirements(subsystem) + } + + + // Called when the command is initially scheduled. + override fun initialize() { + timer.reset() + timer.start() + } + + // Called every time the scheduler runs while the command is scheduled. + override fun execute() { + if (timer.get() < startDelaySecs) { + voltageConsumer.accept(0.0) + } else { + val voltage = (timer.get() - startDelaySecs) * rampRateVoltsPerSec * if (forward) 1 else -1 + voltageConsumer.accept(voltage) + data.add(velocitySupplier.asDouble, voltage) + } + } + + // Called once the command ends or is interrupted. + override fun end(interrupted: Boolean) { + voltageConsumer.accept(0.0) + + timer.stop() + println("hi i ended") + if (!(data.velocityData.size == 0 || data.voltageData.size == 0)) { + val regression = Regression( + data.velocityData.stream().mapToDouble { obj: Double -> obj }.toArray(), + data.voltageData.stream().mapToDouble { obj: Double -> obj }.toArray(), + 1 + ) + println("FF Characterization Results ($name):)\n\tCount= ${data.velocityData.size}\n\tR2=${regression.R2()}\n\tkS: ${regression.beta(0)}\n\tkV: ${regression.beta(1)}") + } + } + + // Returns true when the command should end. + override fun isFinished(): Boolean { + return false + } + + class FeedForwardCharacterizationData(private val name: String) { + val velocityData: MutableList = LinkedList() + val voltageData: MutableList = LinkedList() + fun add(velocity: Double, voltage: Double) { + if (abs(velocity) > 1E-4) { + velocityData.add(abs(velocity)) + voltageData.add(abs(voltage)) + } + } + } + + companion object { + private const val startDelaySecs = 1.5 + private const val rampRateVoltsPerSec = 0.085 + } +} \ No newline at end of file diff --git a/src/main/kotlin/frc/team449/robot2023/commands/characterization/Regression.kt b/src/main/kotlin/frc/team449/robot2023/commands/characterization/Regression.kt new file mode 100644 index 0000000..fec1213 --- /dev/null +++ b/src/main/kotlin/frc/team449/robot2023/commands/characterization/Regression.kt @@ -0,0 +1,184 @@ +// Copyright (c) 2023 FRC 6328 +// http://github.com/Mechanical-Advantage +// +// Use of this source code is governed by an MIT-style +// license that can be found in the LICENSE file at +// the root directory of this project. +package frc.team449.robot2023.commands.characterization + +import Jama.Matrix +import Jama.QRDecomposition +import kotlin.math.abs +import kotlin.math.max +import kotlin.math.pow + +// NOTE: This file is available at +// http://algs4.cs.princeton.edu/14analysis/PolynomialRegression.java.html +/** + * The `PolynomialRegression` class performs a polynomial regression on an set of *N* + * data points (*yi*, *xi*). That is, it fits a polynomial + * *y* = 0 + 1 *x* + 2 + * *x*2 + ... + *d* *x**d* (where + * *y* is the response variable, *x* is the predictor variable, and the + * *i* are the regression coefficients) that minimizes the sum of squared + * residuals of the multiple regression model. It also computes associated the coefficient of + * determination *R*2. + * + * + * This implementation performs a QR-decomposition of the underlying Vandermonde matrix, so it is + * neither the fastest nor the most numerically stable way to perform the polynomial regression. + * + * @author Robert Sedgewick + * @author Kevin Wayne + */ +class Regression @JvmOverloads constructor( + x: DoubleArray, y: DoubleArray, // degree of the polynomial regression + private var degree: Int, // name of the predictor variable + private var variableName: String = "n" +) : Comparable { + private val beta // the polynomial regression coefficients + : Matrix + private val sse // sum of squares due to error + : Double + private var sst = 0.0 // total sum of squares + + init { + val n = x.size + var qr: QRDecomposition? + var matrixX: Matrix? + + // in case Vandermonde matrix does not have full rank, reduce degree until it + // does + while (true) { + + // build Vandermonde matrix + val vandermonde = Array(n) { DoubleArray(degree + 1) } + for (i in 0 until n) { + for (j in 0..degree) { + vandermonde[i][j] = x[i].pow(j.toDouble()) + } + } + matrixX = Matrix(vandermonde) + + // find least squares solution + qr = QRDecomposition(matrixX) + if (qr.isFullRank()) break + + // decrease degree and try again + degree-- + } + + // create matrix from vector + val matrixY = Matrix(y, n) + + // linear regression coefficients + beta = qr!!.solve(matrixY) + + // mean of y[] values + var sum = 0.0 + for (i in 0 until n) sum += y[i] + val mean = sum / n + + // total variation to be accounted for + for (i in 0 until n) { + val dev = y[i] - mean + sst += dev * dev + } + + // variation not accounted for + val residuals: Matrix? = matrixX!!.times(beta).minus(matrixY) + sse = residuals!!.norm2() * residuals.norm2() + } + + /** + * Returns the `j`th regression coefficient. + * + * @param j the index + * @return the `j`th regression coefficient + */ + fun beta(j: Int): Double { + // to make -0.0 print as 0.0 + return if (abs(beta.get(j, 0)) < 1E-4) 0.0 else beta.get(j, 0) + } + + /** + * Returns the degree of the polynomial to fit. + * + * @return the degree of the polynomial to fit + */ + private fun degree(): Int { + return degree + } + + /** + * Returns the coefficient of determination *R*2. + * + * @return the coefficient of determination *R*2, which is a real number between + * 0 and 1 + */ + fun R2(): Double { + return if (sst == 0.0) 1.0 else 1.0 - sse / sst // constant function + } + + /** + * Returns the expected response `y` given the value of the predictor variable `x`. + * + * @param x the value of the predictor variable + * @return the expected response `y` given the value of the predictor variable `x` + */ + fun predict(x: Double): Double { + // horner's method + var y = 0.0 + for (j in degree downTo 0) y = beta(j) + x * y + return y + } + + /** + * Returns a string representation of the polynomial regression model. + * + * @return a string representation of the polynomial regression model, including the best-fit + * polynomial and the coefficient of determination *R*2 + */ + override fun toString(): String { + var s = StringBuilder() + var j = degree + + // ignoring leading zero coefficients + while (j >= 0 && abs(beta(j)) < 1E-5) j-- + + // create remaining terms + while (j >= 0) { + when (j) { + 0 -> s.append(String.format("%.10f ", beta(j))) + 1 -> s.append(String.format("%.10f %s + ", beta(j), variableName)) + else -> s.append( + String.format( + "%.10f %s^%d + ", beta(j), + variableName, j + ) + ) + } + j-- + } + s = s.append(" (R^2 = " + String.format("%.3f", R2()) + ")") + + // replace "+ -2n" with "- 2n" + return s.toString().replace("+ -", "- ") + } + + /** Compare lexicographically. */ + override fun compareTo(other: Regression?): Int { + val EPSILON = 1E-5 + val maxDegree = max(degree().toDouble(), other!!.degree().toDouble()).toInt() + for (j in maxDegree downTo 0) { + var term1 = 0.0 + var term2 = 0.0 + if (degree() >= j) term1 = beta(j) + if (other.degree() >= j) term2 = other.beta(j) + if (abs(term1) < EPSILON) term1 = 0.0 + if (abs(term2) < EPSILON) term2 = 0.0 + if (term1 < term2) return -1 else if (term1 > term2) return +1 + } + return 0 + } +} \ No newline at end of file diff --git a/src/main/kotlin/frc/team449/robot2023/commands/driveAlign/OrbitAlign.kt b/src/main/kotlin/frc/team449/robot2023/commands/driveAlign/OrbitAlign.kt new file mode 100644 index 0000000..bc5aaa5 --- /dev/null +++ b/src/main/kotlin/frc/team449/robot2023/commands/driveAlign/OrbitAlign.kt @@ -0,0 +1,55 @@ +package frc.team449.robot2023.commands.driveAlign + +import edu.wpi.first.math.MathUtil +import edu.wpi.first.math.controller.PIDController +import edu.wpi.first.math.geometry.Translation2d +import edu.wpi.first.math.kinematics.ChassisSpeeds +import edu.wpi.first.wpilibj2.command.Command +import frc.team449.control.DriveSubsystem +import frc.team449.control.OI +import frc.team449.robot2023.constants.RobotConstants +import frc.team449.robot2023.constants.auto.AutoConstants + +/** + * @param drive The holonomic drive you want to align with + * @param point The point in 2d space you want the drivetrain to face towards + * @param headingPID The non-Profiled PID controller you want to use for fixing rotational error + */ +class OrbitAlign( + private val drive: DriveSubsystem, + private val oi: OI, + private val point: Translation2d, + private val headingPID: PIDController = PIDController( + AutoConstants.ORBIT_KP, + 0.0, + 0.0 + ) +) : Command() { + + init { + addRequirements(drive) + headingPID.enableContinuousInput(-Math.PI, Math.PI) + headingPID.setTolerance(0.015) + } + + private var fieldToRobot = Translation2d() + private var robotToPoint = Translation2d() + + override fun execute() { + fieldToRobot = drive.pose.translation + robotToPoint = point - fieldToRobot + headingPID.setpoint = robotToPoint.angle.radians + + drive.set( + ChassisSpeeds( + oi.get().vxMetersPerSecond, + oi.get().vyMetersPerSecond, + MathUtil.clamp(headingPID.calculate(drive.heading.radians), -RobotConstants.MAX_ROT_SPEED, RobotConstants.MAX_ROT_SPEED) + ) + ) + } + + override fun end(interrupted: Boolean) { + drive.stop() + } +} diff --git a/src/main/kotlin/frc/team449/robot2023/commands/driveAlign/ProfiledPoseAlign.kt b/src/main/kotlin/frc/team449/robot2023/commands/driveAlign/ProfiledPoseAlign.kt new file mode 100644 index 0000000..297c0fe --- /dev/null +++ b/src/main/kotlin/frc/team449/robot2023/commands/driveAlign/ProfiledPoseAlign.kt @@ -0,0 +1,119 @@ +package frc.team449.robot2023.commands.driveAlign + +import edu.wpi.first.math.controller.PIDController +import edu.wpi.first.math.geometry.Pose2d +import edu.wpi.first.math.geometry.Rotation2d +import edu.wpi.first.math.kinematics.ChassisSpeeds +import edu.wpi.first.math.trajectory.TrapezoidProfile +import edu.wpi.first.wpilibj.Timer +import edu.wpi.first.wpilibj2.command.Command +import frc.team449.control.holonomic.SwerveDrive +import frc.team449.robot2023.constants.RobotConstants +import frc.team449.robot2023.constants.auto.AutoConstants +import kotlin.math.PI +import kotlin.math.hypot + +/** + * @param drive The holonomic drive you want to align with + * @param targetPose The pose you want to drive up to + * @param xPID The profiled PID controller with constraints you want to use for fixing X error + * @param yPID The profiled PID controller with constraints you want to use for fixing Y error + * @param headingPID The non-Profiled PID controller you want to use for fixing rotational error + * @param tolerance The allowed tolerance from the targetPose + */ +class ProfiledPoseAlign( + private val drive: SwerveDrive, + private val targetPose: Pose2d, + private val xSpeed: Double, + private val ySpeed: Double, + private val xPID: PIDController = PIDController( + AutoConstants.DEFAULT_X_KP, + 0.0, + 0.0 + ), + private val yPID: PIDController = PIDController( + AutoConstants.DEFAULT_Y_KP, + 0.0, + 0.0 + ), + private val headingPID: PIDController = PIDController( + AutoConstants.DEFAULT_ROTATION_KP, + 0.0, + 0.0 + ), + private val xProfile: TrapezoidProfile = TrapezoidProfile(TrapezoidProfile.Constraints(RobotConstants.MAX_LINEAR_SPEED - 1.25, 2.25)), + private val yProfile: TrapezoidProfile = TrapezoidProfile(TrapezoidProfile.Constraints(RobotConstants.MAX_LINEAR_SPEED - 1.25, 2.25)), + private val tolerance: Pose2d = Pose2d(0.05, 0.05, Rotation2d(0.05)), + private val speedTol: Double = 0.05, + private val speedTolRot: Double = 0.05 +) : Command() { + init { + addRequirements(drive) + } + + val timer = Timer() + + override fun initialize() { + headingPID.enableContinuousInput(-PI, PI) + + // Set tolerances from the given pose tolerance + xPID.setTolerance(tolerance.x) + yPID.setTolerance(tolerance.y) + headingPID.setTolerance(tolerance.rotation.radians) + + headingPID.setpoint = targetPose.rotation.radians + + timer.restart() + } + + fun getTime(): Double { + return maxOf(xProfile.totalTime(), yProfile.totalTime(), 0.5) + } + + override fun execute() { + val currTime = timer.get() + + // Calculate the feedback for X, Y, and theta using their respective controllers + + val xProfCalc = xProfile.calculate( + currTime, + TrapezoidProfile.State(targetPose.x, 0.0), + TrapezoidProfile.State(drive.pose.x, xSpeed) + ) + + val yProfCalc = yProfile.calculate( + currTime, + TrapezoidProfile.State(targetPose.y, 0.0), + TrapezoidProfile.State(drive.pose.y, ySpeed) + ) + + val xFeedback = xPID.calculate(drive.pose.x, xProfCalc.position) + val yFeedback = yPID.calculate(drive.pose.y, yProfCalc.position) + val headingFeedback = headingPID.calculate(drive.heading.radians) + + drive.set( + ChassisSpeeds.fromFieldRelativeSpeeds( + xFeedback + xProfCalc.velocity, + yFeedback + yProfCalc.velocity, + headingFeedback, + drive.heading + ) + ) + } + + override fun isFinished(): Boolean { + val currTime = timer.get() + + return xPID.atSetpoint() && yPID.atSetpoint() && headingPID.atSetpoint() && + xProfile.isFinished(currTime) && yProfile.isFinished(currTime) && + hypot( + drive.currentSpeeds.vxMetersPerSecond, + drive.currentSpeeds.vyMetersPerSecond + ) < speedTol && + drive.currentSpeeds.omegaRadiansPerSecond < speedTolRot + } + + override fun end(interrupted: Boolean) { + drive.stop() + } +} diff --git a/src/main/kotlin/frc/team449/robot2023/commands/light/BlairChasing.kt b/src/main/kotlin/frc/team449/robot2023/commands/light/BlairChasing.kt new file mode 100644 index 0000000..1cf81fb --- /dev/null +++ b/src/main/kotlin/frc/team449/robot2023/commands/light/BlairChasing.kt @@ -0,0 +1,45 @@ +package frc.team449.robot2023.commands.light + +import edu.wpi.first.math.MathUtil +import edu.wpi.first.wpilibj2.command.Command +import frc.team449.robot2023.constants.subsystem.LightConstants +import frc.team449.robot2023.subsystems.light.Light + +/** Description: Have a linear transition from white to red */ +class BlairChasing( + private val led: Light +) : Command() { + + init { + addRequirements(led) + } + + override fun runsWhenDisabled(): Boolean { + return true + } + + private var firstSaturation1 = 0.0 + private var firstSaturation2 = 0.0 + + override fun execute() { + for (i in LightConstants.SECTION_1_START..LightConstants.SECTION_1_END) { + // This number is related to how many lights will show up between the high and low intensity (which technically also affects how fast itll cycle) + val saturation = MathUtil.inputModulus(firstSaturation1 + i * 200.0 / led.buffer.length, 0.0, 255.0) + led.setHSV(i, 0, saturation.toInt(), 255) + + // The i * 255.0 relates to how fast it will cycle in between the high and low intensity + firstSaturation1 += 0.135 + firstSaturation1 = MathUtil.inputModulus(firstSaturation1, 0.0, 255.0) + } + + for (i in LightConstants.SECTION_2_START..LightConstants.SECTION_2_END) { + // This number is related to how many lights will show up between the high and low intensity (which technically also affects how fast itll cycle) + val saturation = MathUtil.inputModulus(firstSaturation2 + (i - LightConstants.SECTION_2_START) * 200.0 / led.buffer.length, 0.0, 255.0) + led.setHSV(i, 0, saturation.toInt(), 255) + + // The i * 255.0 relates to how fast it will cycle in between the high and low intensity + firstSaturation2 += 0.135 + firstSaturation2 = MathUtil.inputModulus(firstSaturation2, 0.0, 255.0) + } + } +} diff --git a/src/main/kotlin/frc/team449/robot2023/commands/light/BreatheHue.kt b/src/main/kotlin/frc/team449/robot2023/commands/light/BreatheHue.kt new file mode 100644 index 0000000..4fc7a9f --- /dev/null +++ b/src/main/kotlin/frc/team449/robot2023/commands/light/BreatheHue.kt @@ -0,0 +1,47 @@ +package frc.team449.robot2023.commands.light + +import edu.wpi.first.math.MathUtil +import edu.wpi.first.wpilibj2.command.Command +import frc.team449.robot2023.constants.subsystem.LightConstants +import frc.team449.robot2023.subsystems.light.Light + +/** Description: Have a linear transition from a darker to brighter specified hue */ +class BreatheHue( + private val led: Light, + private val hue: Int +) : Command() { + + init { + addRequirements(led) + } + + override fun runsWhenDisabled(): Boolean { + return true + } + + private var firstIntensity1 = 175.0 + private var firstIntensity2 = 175.0 + + + override fun execute() { + for (i in LightConstants.SECTION_1_START..LightConstants.SECTION_1_END) { + // This number is related to how many lights will show up between the high and low intensity + val intensity = MathUtil.inputModulus(firstIntensity1 + i * 32.5 / led.buffer.length, 125.0, 255.0) + led.setHSV(i, hue, 255, intensity.toInt()) + + // The i * 255.0 relates to how fast it will cycle in between the high and low intensity + firstIntensity1 += 0.1 + firstIntensity1 = MathUtil.inputModulus(firstIntensity1, 125.0, 255.0) + } + + for (i in LightConstants.SECTION_2_START..LightConstants.SECTION_2_END) { + // This number is related to how many lights will show up between the high and low intensity + val intensity = MathUtil.inputModulus(firstIntensity2 + (i - LightConstants.SECTION_2_START) * 32.5 / led.buffer.length, 125.0, 255.0) + led.setHSV(i, hue, 255, intensity.toInt()) + + // The i * 255.0 relates to how fast it will cycle in between the high and low intensity + firstIntensity2 += 0.1 + firstIntensity2 = MathUtil.inputModulus(firstIntensity2, 125.0, 255.0) + } + } +} diff --git a/src/main/kotlin/frc/team449/robot2023/commands/light/Crazy.kt b/src/main/kotlin/frc/team449/robot2023/commands/light/Crazy.kt new file mode 100644 index 0000000..ee3ba56 --- /dev/null +++ b/src/main/kotlin/frc/team449/robot2023/commands/light/Crazy.kt @@ -0,0 +1,26 @@ +package frc.team449.robot2023.commands.light + +import edu.wpi.first.wpilibj2.command.Command +import frc.team449.robot2023.subsystems.light.Light +import kotlin.random.Random + +/** Description: Have a random color set for every led every 20ms + * a.k.a. you go blind */ +class Crazy( + private val led: Light +) : Command() { + + init { + addRequirements(led) + } + + override fun runsWhenDisabled(): Boolean { + return true + } + + override fun execute() { + for (i in 0 until led.buffer.length) { + led.setRGB(i, Random.nextInt(0, 256), Random.nextInt(0, 256), Random.nextInt(0, 256)) + } + } +} diff --git a/src/main/kotlin/frc/team449/robot2023/commands/light/PickupBlink.kt b/src/main/kotlin/frc/team449/robot2023/commands/light/PickupBlink.kt new file mode 100644 index 0000000..078315d --- /dev/null +++ b/src/main/kotlin/frc/team449/robot2023/commands/light/PickupBlink.kt @@ -0,0 +1,33 @@ +package frc.team449.robot2023.commands.light + +import edu.wpi.first.wpilibj2.command.Command +import edu.wpi.first.wpilibj2.command.InstantCommand +import edu.wpi.first.wpilibj2.command.SequentialCommandGroup +import edu.wpi.first.wpilibj2.command.WaitCommand +import frc.team449.robot2023.subsystems.light.Light + +/** Description: Blink a certain color 5 times */ +class PickupBlink { + fun blinkGreen(light: Light): Command { + val cmdGroup = SequentialCommandGroup() + + cmdGroup.addRequirements(light) + + for (x in 0 until 5) { + cmdGroup.addCommands(InstantCommand({ setColor(light, 0, 255, 0) })) + cmdGroup.addCommands(WaitCommand(0.1)) + cmdGroup.addCommands(InstantCommand({ setColor(light, 0, 0, 0) })) + cmdGroup.addCommands(WaitCommand(0.1)) + } + + cmdGroup.ignoringDisable(true) + + return cmdGroup + } + + private fun setColor(led: Light, r: Int, g: Int, b: Int) { + for (i in 0 until led.buffer.length) { + led.setRGB(i, r, g, b) + } + } +} diff --git a/src/main/kotlin/frc/team449/robot2023/commands/light/Rainbow.kt b/src/main/kotlin/frc/team449/robot2023/commands/light/Rainbow.kt new file mode 100644 index 0000000..cc822cd --- /dev/null +++ b/src/main/kotlin/frc/team449/robot2023/commands/light/Rainbow.kt @@ -0,0 +1,38 @@ +package frc.team449.robot2023.commands.light + +import edu.wpi.first.math.MathUtil +import edu.wpi.first.wpilibj2.command.Command +import frc.team449.robot2023.constants.subsystem.LightConstants +import frc.team449.robot2023.subsystems.light.Light + +class Rainbow( + private val led: Light +) : Command() { + + init { + addRequirements(led) + } + + override fun runsWhenDisabled(): Boolean { + return true + } + + private var firstHue = 0.0 + + override fun execute() { + for (i in LightConstants.SECTION_1_START..LightConstants.SECTION_1_END) { + val hue = MathUtil.inputModulus(firstHue + i * 180 / (LightConstants.SECTION_1_END - LightConstants.SECTION_1_START), 0.0, 180.0) + + led.setHSV(i, hue.toInt(), 255, 255) + } + + for (i in LightConstants.SECTION_2_START..LightConstants.SECTION_2_END) { + val hue = MathUtil.inputModulus(firstHue + (i - LightConstants.SECTION_2_START) * 180 / (LightConstants.SECTION_2_END - LightConstants.SECTION_2_START), 0.0, 180.0) + + led.setHSV(i, hue.toInt(), 255, 255) + } + + firstHue += 6.15 + firstHue = MathUtil.inputModulus(firstHue, 0.0, 180.0) + } +} diff --git a/src/main/kotlin/frc/team449/robot2023/commands/light/SolidColor.kt b/src/main/kotlin/frc/team449/robot2023/commands/light/SolidColor.kt new file mode 100644 index 0000000..0449d6a --- /dev/null +++ b/src/main/kotlin/frc/team449/robot2023/commands/light/SolidColor.kt @@ -0,0 +1,27 @@ +package frc.team449.robot2023.commands.light + +import edu.wpi.first.wpilibj2.command.Command +import frc.team449.robot2023.subsystems.light.Light + +/** Description: Have a solid color */ +class SolidColor( + private val led: Light, + private val r: Int, + private val g: Int, + private val b: Int +) : Command() { + + init { + addRequirements(led) + } + + override fun runsWhenDisabled(): Boolean { + return true + } + + override fun execute() { + for (i in 0 until led.buffer.length) { + led.setRGB(i, r, g, b) + } + } +} diff --git a/src/main/kotlin/frc/team449/robot2023/constants/MotorConstants.kt b/src/main/kotlin/frc/team449/robot2023/constants/MotorConstants.kt new file mode 100644 index 0000000..e760563 --- /dev/null +++ b/src/main/kotlin/frc/team449/robot2023/constants/MotorConstants.kt @@ -0,0 +1,12 @@ +package frc.team449.robot2023.constants + +import edu.wpi.first.math.util.Units + +object MotorConstants { + /** NEO characteristics */ + const val NOMINAL_VOLTAGE = 12.0 + const val STALL_TORQUE = 3.36 + const val STALL_CURRENT = 166.0 + const val FREE_CURRENT = 1.3 + val FREE_SPEED = Units.rotationsPerMinuteToRadiansPerSecond(5676.0) +} diff --git a/src/main/kotlin/frc/team449/robot2023/constants/RobotConstants.kt b/src/main/kotlin/frc/team449/robot2023/constants/RobotConstants.kt new file mode 100644 index 0000000..380f395 --- /dev/null +++ b/src/main/kotlin/frc/team449/robot2023/constants/RobotConstants.kt @@ -0,0 +1,61 @@ +package frc.team449.robot2023.constants + +import edu.wpi.first.math.controller.PIDController +import edu.wpi.first.math.geometry.Pose2d +import edu.wpi.first.math.geometry.Rotation2d +import edu.wpi.first.math.system.plant.DCMotor +import edu.wpi.first.math.util.Units +import frc.team449.robot2023.constants.drives.SwerveConstants +import kotlin.math.PI + +object RobotConstants { + + /** Other CAN ID */ + const val PDH_CAN = 1 + + /** Controller Configurations */ + const val ROT_RATE_LIMIT = 4.0 * PI + const val NEG_ROT_RATE_LIM = -8.0 * PI + const val TRANSLATION_DEADBAND = .15 + const val ROTATION_DEADBAND = .15 + + /** In kilograms, include bumpers and battery and all */ + const val ROBOT_WEIGHT = 55 + + /** Drive configuration */ + const val MAX_LINEAR_SPEED = SwerveConstants.MAX_ATTAINABLE_MK4I_SPEED // m/s + const val MAX_ROT_SPEED = PI // rad/s + val MAX_ACCEL = 4 * DCMotor( + MotorConstants.NOMINAL_VOLTAGE, + MotorConstants.STALL_TORQUE * SwerveConstants.EFFICIENCY, + MotorConstants.STALL_CURRENT, + MotorConstants.FREE_CURRENT, + MotorConstants.FREE_SPEED, + 1 + ).getTorque(55.0) / + (Units.inchesToMeters(2.0) * ROBOT_WEIGHT * SwerveConstants.DRIVE_GEARING) // m/s/s + + val INITIAL_POSE = Pose2d(0.0, 0.0, Rotation2d.fromDegrees(0.0)) + + + init { + println("Max Accel $MAX_ACCEL") + } + + const val LOOP_TIME = 0.020 + + /** PID controller for Orthogonal turning */ + val ORTHOGONAL_CONTROLLER = PIDController( + 3.0, + 0.0, + 0.0 + ) + + const val ALIGN_ROT_SPEED = 3 * PI / 2 + + val IR_CHANNEL = 15 + + // Robot dimensions (INCLUDING BUMPERS) + val ROBOT_WIDTH = Units.inchesToMeters(27.0 + 3.25 * 2) + val ROBOT_LENGTH = Units.inchesToMeters(30.0 + 3.25 * 2) +} diff --git a/src/main/kotlin/frc/team449/robot2023/constants/auto/AutoConstants.kt b/src/main/kotlin/frc/team449/robot2023/constants/auto/AutoConstants.kt new file mode 100644 index 0000000..55f3ee0 --- /dev/null +++ b/src/main/kotlin/frc/team449/robot2023/constants/auto/AutoConstants.kt @@ -0,0 +1,12 @@ +package frc.team449.robot2023.constants.auto + +import kotlin.math.PI + +object AutoConstants { + /** PID gains */ + const val DEFAULT_X_KP = 1.875 + const val DEFAULT_Y_KP = 1.875 + const val DEFAULT_ROTATION_KP = 2.0 + + const val ORBIT_KP = 2 * PI +} diff --git a/src/main/kotlin/frc/team449/robot2023/constants/drives/DifferentialConstants.kt b/src/main/kotlin/frc/team449/robot2023/constants/drives/DifferentialConstants.kt new file mode 100644 index 0000000..0092955 --- /dev/null +++ b/src/main/kotlin/frc/team449/robot2023/constants/drives/DifferentialConstants.kt @@ -0,0 +1,53 @@ +package frc.team449.robot2023.constants.drives + +import edu.wpi.first.math.controller.DifferentialDriveFeedforward +import edu.wpi.first.math.util.Units +import edu.wpi.first.wpilibj.Encoder +import java.lang.Math.PI + +/** Constants for a differential drivetrain */ +object DifferentialConstants { + + /** Drive motor CAN ID */ + const val DRIVE_MOTOR_L = 2 + const val DRIVE_MOTOR_L1 = 4 + const val DRIVE_MOTOR_L2 = 3 + const val DRIVE_MOTOR_R = 1 + const val DRIVE_MOTOR_R1 = 11 + const val DRIVE_MOTOR_R2 = 7 + + /** Angular feed forward gains. */ + const val DRIVE_ANGLE_FF_KS = 0.20112 + const val DRIVE_ANGLE_FF_KV = 10.05 + const val DRIVE_ANGLE_FF_KA = 0.505 + + /** Control Constants */ + const val DRIVE_KP = .0 + const val DRIVE_KI = .0 + const val DRIVE_KD = .0 + const val DRIVE_FF_KS = 0.1908 + const val DRIVE_FF_KV = 2.5406 + const val DRIVE_FF_KA = 0.44982 + + /** Encoder Characteristics */ + val DRIVE_ENC_RIGHT = Encoder(4, 5) + val DRIVE_ENC_LEFT = Encoder(6, 7) + const val NEO_ENCODER_CPR = 1 + const val DRIVE_EXT_ENC_CPR = 256 + + /** Drive Characteristics */ + const val DRIVE_GEARING = 1.0 + val DRIVE_WHEEL_RADIUS = Units.inchesToMeters(2.0) + val DRIVE_UPR = 2 * PI * DRIVE_WHEEL_RADIUS + const val DRIVE_CURRENT_LIM = 35 + const val DRIVE_ENC_VEL_THRESHOLD = 999999.0 + const val TRACK_WIDTH = .615 // m + + val DRIVE_FEED_FORWARD = DifferentialDriveFeedforward( + DRIVE_FF_KV, + DRIVE_FF_KA, + DRIVE_ANGLE_FF_KV, + DRIVE_ANGLE_FF_KA, + TRACK_WIDTH + ) +} diff --git a/src/main/kotlin/frc/team449/robot2023/constants/drives/MecanumConstants.kt b/src/main/kotlin/frc/team449/robot2023/constants/drives/MecanumConstants.kt new file mode 100644 index 0000000..24ac303 --- /dev/null +++ b/src/main/kotlin/frc/team449/robot2023/constants/drives/MecanumConstants.kt @@ -0,0 +1,30 @@ +package frc.team449.robot2023.constants.drives + +import edu.wpi.first.math.util.Units + +object MecanumConstants { + + /** Drive motor ports */ + const val DRIVE_MOTOR_FL = 1 + const val DRIVE_MOTOR_FR = 2 + const val DRIVE_MOTOR_BL = 3 + const val DRIVE_MOTOR_BR = 4 + + /** Feed forward values for driving each module */ + const val DRIVE_KS = 0.16475 + const val DRIVE_KV = 2.0909 + const val DRIVE_KA = 0.29862 + + /** PID gains for driving each module*/ + const val DRIVE_KP = 0.35 + const val DRIVE_KI = 0.0 + const val DRIVE_KD = 0.0 + + /** Drive configuration */ + const val DRIVE_GEARING = 1 / 8.0 + val DRIVE_UPR = Math.PI * Units.inchesToMeters(6.0) + const val MAX_ATTAINABLE_WHEEL_SPEED = (12 - DRIVE_KS) / DRIVE_KV + val WHEELBASE = Units.inchesToMeters(21.426) + val TRACKWIDTH = Units.inchesToMeters(21.000) + const val CURRENT_LIM = 40 +} diff --git a/src/main/kotlin/frc/team449/robot2023/constants/drives/SwerveConstants.kt b/src/main/kotlin/frc/team449/robot2023/constants/drives/SwerveConstants.kt new file mode 100644 index 0000000..3c2a48b --- /dev/null +++ b/src/main/kotlin/frc/team449/robot2023/constants/drives/SwerveConstants.kt @@ -0,0 +1,61 @@ +package frc.team449.robot2023.constants.drives + +import edu.wpi.first.math.util.Units + +object SwerveConstants { + const val EFFICIENCY = 0.95 + + /** Drive motor ports */ + const val DRIVE_MOTOR_FL = 11 + const val DRIVE_MOTOR_FR = 17 + const val DRIVE_MOTOR_BL = 38 + const val DRIVE_MOTOR_BR = 22 + const val TURN_MOTOR_FL = 20 + const val TURN_MOTOR_FR = 3 + const val TURN_MOTOR_BL = 41 + const val TURN_MOTOR_BR = 45 + + /** Turning encoder channels */ + const val TURN_ENC_CHAN_FL = 6 + const val TURN_ENC_CHAN_FR = 9 + const val TURN_ENC_CHAN_BL = 5 + const val TURN_ENC_CHAN_BR = 8 + + /** Offsets for the absolute encoders in rotations */ + const val TURN_ENC_OFFSET_FL = 0.396987 + const val TURN_ENC_OFFSET_FR = 0.389095 + const val TURN_ENC_OFFSET_BL = 0.787267 - 0.5 + const val TURN_ENC_OFFSET_BR = 0.215026 + + /** PID gains for turning each module */ + const val TURN_KP = 0.85 + const val TURN_KI = 0.0 + const val TURN_KD = 0.0 + + /** Feed forward values for driving each module */ + const val DRIVE_KS = 0.2491250419322037 + const val DRIVE_KV = 2.352910954352485 + const val DRIVE_KA = 0.42824 + + // TODO: Figure out this value + const val STEER_KS = 1.0 + + /** PID gains for driving each module*/ + const val DRIVE_KP = 0.4 + const val DRIVE_KI = 0.0 + const val DRIVE_KD = 0.0 + + /** Drive configuration */ + const val DRIVE_GEARING = 1 / 6.12 + const val DRIVE_UPR = 0.31818905832 + const val TURN_UPR = 2 * Math.PI + const val MAX_ATTAINABLE_MK4I_SPEED = (12 - DRIVE_KS) / DRIVE_KV + const val DRIVE_CURRENT_LIM = 55 + const val STEERING_CURRENT_LIM = 40 + const val JOYSTICK_FILTER_ORDER = 2 + + /** Wheelbase = wheel-to-wheel distance from front to back of the robot */ + /** Trackwidth = wheel-to-wheel distance from side to side of the robot */ + val WHEELBASE = Units.inchesToMeters(24.75) // ex. FL to BL + val TRACKWIDTH = Units.inchesToMeters(21.75) // ex. BL to BR +} diff --git a/src/main/kotlin/frc/team449/robot2023/constants/field/FieldConstants.kt b/src/main/kotlin/frc/team449/robot2023/constants/field/FieldConstants.kt new file mode 100644 index 0000000..a6071ba --- /dev/null +++ b/src/main/kotlin/frc/team449/robot2023/constants/field/FieldConstants.kt @@ -0,0 +1,43 @@ +package frc.team449.robot2023.constants.field + +import edu.wpi.first.math.geometry.Pose2d +import edu.wpi.first.math.geometry.Rotation2d +import edu.wpi.first.math.util.Units +import frc.team449.robot2023.constants.RobotConstants + +object FieldConstants { + val fieldLength = Units.feetToMeters(54.0) + val fieldWidth = Units.feetToMeters(27.0) + + val wallNodeY = Units.inchesToMeters(20.19) + val nodeSeparationY = Units.inchesToMeters(22.0) + + val nodeX = Units.inchesToMeters(54.05) + RobotConstants.ROBOT_LENGTH / 2 + + val midNodeFromEdge = Units.inchesToMeters(22.7) + val highNodeFromEdge = Units.inchesToMeters(39.73) + + val PlacementPositions: Map = mapOf( + TargetPosition.Position1 to Pose2d(nodeX, wallNodeY, Rotation2d()), + TargetPosition.Position2 to Pose2d(nodeX, wallNodeY + nodeSeparationY, Rotation2d()), + TargetPosition.Position3 to Pose2d(nodeX, wallNodeY + 2 * nodeSeparationY, Rotation2d()), + TargetPosition.Position4 to Pose2d(nodeX, wallNodeY + 3 * nodeSeparationY, Rotation2d()), + TargetPosition.Position5 to Pose2d(nodeX, wallNodeY + 4 * nodeSeparationY, Rotation2d()), + TargetPosition.Position6 to Pose2d(nodeX, wallNodeY + 5 * nodeSeparationY, Rotation2d()), + TargetPosition.Position7 to Pose2d(nodeX, wallNodeY + 6 * nodeSeparationY, Rotation2d()), + TargetPosition.Position8 to Pose2d(nodeX, wallNodeY + 7 * nodeSeparationY, Rotation2d()), + TargetPosition.Position9 to Pose2d(nodeX, wallNodeY + 8 * nodeSeparationY, Rotation2d()) + ) + + enum class TargetPosition { + Position1, + Position2, + Position3, + Position4, + Position5, + Position6, + Position7, + Position8, + Position9 + } +} diff --git a/src/main/kotlin/frc/team449/robot2023/constants/subsystem/LightConstants.kt b/src/main/kotlin/frc/team449/robot2023/constants/subsystem/LightConstants.kt new file mode 100644 index 0000000..7576685 --- /dev/null +++ b/src/main/kotlin/frc/team449/robot2023/constants/subsystem/LightConstants.kt @@ -0,0 +1,11 @@ +package frc.team449.robot2023.constants.subsystem + +object LightConstants { + const val LIGHT_PORT = 9 + const val LIGHT_LENGTH = 24 + + const val SECTION_1_START = 0 + const val SECTION_1_END = 11 + const val SECTION_2_START = 12 + const val SECTION_2_END = 23 +} diff --git a/src/main/kotlin/frc/team449/robot2023/constants/vision/VisionConstants.kt b/src/main/kotlin/frc/team449/robot2023/constants/vision/VisionConstants.kt new file mode 100644 index 0000000..2f836b7 --- /dev/null +++ b/src/main/kotlin/frc/team449/robot2023/constants/vision/VisionConstants.kt @@ -0,0 +1,93 @@ +package frc.team449.robot2023.constants.vision + +import edu.wpi.first.apriltag.AprilTag +import edu.wpi.first.apriltag.AprilTagFieldLayout +import edu.wpi.first.math.MatBuilder +import edu.wpi.first.math.Matrix +import edu.wpi.first.math.Nat +import edu.wpi.first.math.geometry.Pose3d +import edu.wpi.first.math.geometry.Rotation3d +import edu.wpi.first.math.geometry.Transform3d +import edu.wpi.first.math.geometry.Translation3d +import edu.wpi.first.math.numbers.N1 +import edu.wpi.first.math.numbers.N3 +import edu.wpi.first.math.util.Units +import edu.wpi.first.wpilibj.Filesystem +import frc.team449.control.vision.VisionSubsystem +import org.photonvision.estimation.TargetModel +import org.photonvision.simulation.VisionSystemSim + +/** Constants that have anything to do with vision */ +object VisionConstants { + /** How the tags are laid out on the field (their locations and ids) */ + private val TEST_TAG_LAYOUT = AprilTagFieldLayout( + listOf( + AprilTag(3, Pose3d()) + ), + 16.4846, + 8.1026 + ) + + /** WPILib's AprilTagFieldLayout for the 2023 Charged Up Game */ + val TAG_LAYOUT: AprilTagFieldLayout = AprilTagFieldLayout( + Filesystem.getDeployDirectory().absolutePath.plus("/vision/Bunnybots2023.json") + ) + +// AprilTagFieldLayout.loadFromResource( +// AprilTagFields.k2023ChargedUp.m_resourceFile +// ) + + /** Robot to Camera distance */ + val robotToCamera = Transform3d( + Translation3d(Units.inchesToMeters(-11.48657), Units.inchesToMeters(0.0), Units.inchesToMeters(8.3416)), + Rotation3d(0.0, Units.degreesToRadians(15.0), Units.degreesToRadians(180.0)) + ) + + val TAG_MODEL = TargetModel( + Units.inchesToMeters(6.5), + Units.inchesToMeters(6.5) + ) + + /** Filtering Constants */ + const val MAX_AMBIGUITY = 0.325 + const val MAX_DISTANCE_SINGLE_TAG = 3.45 + const val MAX_DISTANCE_MULTI_TAG = 4.5 + const val SINGLE_TAG_HEADING_MAX_DEV_DEG = 5.0 + const val MAX_HEIGHT_ERR_METERS = 0.075 + const val TAG_MULTIPLIER = 0.5 + + /** Std Dev Calculation Constants */ + const val ORDER = 2 + const val PROPORTION = 1 / 25 + + val VISION_SIM = VisionSystemSim( + "main" + ) + + /** Vision Sim Setup Constants */ + const val SIM_FPS = 25.0 + const val SIM_CAMERA_HEIGHT_PX = 720 + const val SIM_CAMERA_WIDTH_PX = 1280 + const val SIM_FOV_DEG = 75.0 + const val SIM_CALIB_AVG_ERR_PX = 0.35 + const val SIM_CALIB_ERR_STDDEV_PX = 0.10 + const val SIM_AVG_LATENCY = 50.0 + const val SIM_STDDEV_LATENCY = 10.0 + const val ENABLE_WIREFRAME = true + + + /** List of cameras that we want to use */ + val ESTIMATORS: ArrayList = arrayListOf( + VisionSubsystem( + "arducam", + TAG_LAYOUT, + robotToCamera, + VISION_SIM + ) + ) + + val ENCODER_TRUST: Matrix = MatBuilder(Nat.N3(), Nat.N1()).fill(.085, .085, .015) + val SINGLE_TAG_TRUST: Matrix = MatBuilder(Nat.N3(), Nat.N1()).fill(.125, .125, .80) + val MULTI_TAG_TRUST: Matrix = MatBuilder(Nat.N3(), Nat.N1()).fill(.0275, .0275, .30) + +} diff --git a/src/main/kotlin/frc/team449/robot2023/subsystems/ControllerBindings.kt b/src/main/kotlin/frc/team449/robot2023/subsystems/ControllerBindings.kt new file mode 100644 index 0000000..66855b7 --- /dev/null +++ b/src/main/kotlin/frc/team449/robot2023/subsystems/ControllerBindings.kt @@ -0,0 +1,53 @@ +package frc.team449.robot2023.subsystems + +import edu.wpi.first.math.geometry.Rotation2d +import edu.wpi.first.wpilibj.XboxController +import edu.wpi.first.wpilibj2.command.* +import edu.wpi.first.wpilibj2.command.button.JoystickButton +import edu.wpi.first.wpilibj2.command.button.Trigger +import frc.team449.robot2023.Robot +import frc.team449.robot2023.commands.characterization.Characterization +import frc.team449.robot2023.constants.RobotConstants +import kotlin.math.PI + + +class ControllerBindings( + private val driveController: XboxController, + private val mechanismController: XboxController, + private val robot: Robot +) { + + fun bindButtons() { + // slow drive + Trigger { driveController.rightTriggerAxis >= .75 }.onTrue( + InstantCommand({ robot.drive.maxLinearSpeed = 1.0 }).andThen( + InstantCommand({ robot.drive.maxRotSpeed = PI / 4 }) + ) + ).onFalse( + InstantCommand({ robot.drive.maxLinearSpeed = RobotConstants.MAX_LINEAR_SPEED }).andThen( + InstantCommand({ robot.drive.maxRotSpeed = RobotConstants.MAX_ROT_SPEED }) + ) + ) + + // reset gyro + JoystickButton(driveController, XboxController.Button.kStart.value).onTrue( + InstantCommand({ + robot.drive.heading = Rotation2d() + }) + ) + + // characterize + JoystickButton(driveController, XboxController.Button.kA.value).onTrue( + Characterization( + robot.drive, + true, + "swerve drive", + robot.drive::setVoltage, + robot.drive::getModuleVel + ).withInterruptBehavior(Command.InterruptionBehavior.kCancelIncoming) + ).onFalse( + robot.driveCommand + ) + + } +} diff --git a/src/main/kotlin/frc/team449/robot2023/subsystems/light/Light.kt b/src/main/kotlin/frc/team449/robot2023/subsystems/light/Light.kt new file mode 100644 index 0000000..4ca5771 --- /dev/null +++ b/src/main/kotlin/frc/team449/robot2023/subsystems/light/Light.kt @@ -0,0 +1,88 @@ +package frc.team449.robot2023.subsystems.light + +import edu.wpi.first.wpilibj.AddressableLED +import edu.wpi.first.wpilibj.AddressableLEDBuffer +import edu.wpi.first.wpilibj.RobotBase +import edu.wpi.first.wpilibj2.command.SubsystemBase +import frc.team449.robot2023.constants.subsystem.LightConstants + +/** + * Controls an LED strip. + * @param port The PWM port of the LED strip. + * @param length The length of the LED strip. + */ + +class Light( + port: Int, + length: Int +) : SubsystemBase() { + + private val lightStrip = AddressableLED(port) + val buffer = AddressableLEDBuffer(length) + + init { + lightStrip.setLength(buffer.length) + lightStrip.setData(buffer) + lightStrip.start() + } + + override fun periodic() { + lightStrip.setData(buffer) + } + + /** Copy the AddressableLEDBuffer setHsv() except to support + * GRB LED strips */ + fun setHSV(index: Int, h: Int, s: Int, v: Int) { + if (RobotBase.isReal()) { + if (s == 0) { + buffer.setRGB(index, v, v, v) + return + } + + // Difference between highest and lowest value of any rgb component + val chroma = s * v / 255 + + // Because hue is 0-180 rather than 0-360 use 30 not 60 + val region = h / 30 % 6 + + // Remainder converted from 0-30 to 0-255 + val remainder = Math.round(h % 30 * (255 / 30.0)).toInt() + + // Value of the lowest rgb component + val m = v - chroma + + // Goes from 0 to chroma as hue increases + val X = chroma * remainder shr 8 + when (region) { + 0 -> buffer.setRGB(index, X + m, v, m) + 1 -> buffer.setRGB(index, v, v - X, m) + 2 -> buffer.setRGB(index, v, m, X + m) + 3 -> buffer.setRGB(index, v - X, m, v) + 4 -> buffer.setRGB(index, m, X + m, v) + else -> buffer.setRGB(index, m, v, v - X) + } + } else { + buffer.setHSV(index, h, s, v) + } + } + + /** Copy the AddressableLEDBuffer setRGB() except to support + * GRB LED strips */ + fun setRGB(index: Int, r: Int, g: Int, b: Int) { + if (RobotBase.isReal()) { + buffer.setRGB(index, g, r, b) + } else { + buffer.setRGB(index, r, g, b) + } + } + + companion object { + /** Create an LED strip controller using [LightConstants]. */ + fun createLight(): Light { + return Light( + LightConstants.LIGHT_PORT, + LightConstants.LIGHT_LENGTH + ) + } + } +} diff --git a/src/main/kotlin/frc/team449/system/AHRS.kt b/src/main/kotlin/frc/team449/system/AHRS.kt new file mode 100644 index 0000000..f10503f --- /dev/null +++ b/src/main/kotlin/frc/team449/system/AHRS.kt @@ -0,0 +1,83 @@ +package frc.team449.system + +import edu.wpi.first.math.filter.LinearFilter +import edu.wpi.first.math.geometry.Rotation2d +import edu.wpi.first.wpilibj.SPI +import edu.wpi.first.wpilibj.Timer +import edu.wpi.first.wpilibj.simulation.SimDeviceSim +import frc.team449.util.simBooleanProp +import frc.team449.util.simDoubleProp + +class AHRS( + private val navx: com.kauailabs.navx.frc.AHRS +) { + + var prevPos = Double.NaN + var prevTime = Double.NaN + + private val filter = LinearFilter.movingAverage(5) + + /** The current reading of the gyro with the offset included */ + val heading: Rotation2d + get() { + return -Rotation2d.fromDegrees(navx.fusedHeading.toDouble()) + } + + val pitch: Rotation2d + get() { + return -Rotation2d.fromDegrees(navx.pitch.toDouble()) + } + + val roll: Rotation2d + get() { + return -Rotation2d.fromDegrees(navx.roll.toDouble()) + } + + fun angularXVel(): Double { + val currPos = navx.roll.toDouble() + val currTime = Timer.getFPGATimestamp() + + val vel = if (prevPos.isNaN()) { + 0.0 + } else { + val dt = currTime - prevTime + val dx = currPos - prevPos + dx / dt + } + this.prevTime = currTime + this.prevPos = currPos + return filter.calculate(vel) + } + + constructor( + port: SPI.Port = SPI.Port.kMXP + ) : this( + com.kauailabs.navx.frc.AHRS(port) + ) + + fun calibrated(): Boolean { + return navx.isMagnetometerCalibrated + } + + /** + * Used to set properties of an [AHRS] object during simulation. See + * https://pdocs.kauailabs.com/navx-mxp/softwa + * re/roborio-libraries/java/ + * + * @param devName The name of the simulated device. + * @param index The NavX index. + */ + class SimController(devName: String = "navX-Sensor", index: Int = 0) { + private val deviceSim = SimDeviceSim(devName, index) + + var isConnected by simBooleanProp(deviceSim.getBoolean("Connected")) + var yaw by simDoubleProp(deviceSim.getDouble("Yaw")) + var pitch by simDoubleProp(deviceSim.getDouble("Pitch")) + var roll by simDoubleProp(deviceSim.getDouble("Roll")) + var compassHeading by simDoubleProp(deviceSim.getDouble("CompassHeading")) + var fusedHeading by simDoubleProp(deviceSim.getDouble("FusedHeading")) + var linearWorldAccelX by simDoubleProp(deviceSim.getDouble("LinearWorldAccelX")) + var linearWorldAccelY by simDoubleProp(deviceSim.getDouble("LinearWorldAccelX")) + var linearWorldAccelZ by simDoubleProp(deviceSim.getDouble("LinearWorldAccelY")) + } +} diff --git a/src/main/kotlin/frc/team449/system/SimBattery.kt b/src/main/kotlin/frc/team449/system/SimBattery.kt new file mode 100644 index 0000000..463e17d --- /dev/null +++ b/src/main/kotlin/frc/team449/system/SimBattery.kt @@ -0,0 +1,27 @@ +package frc.team449.system + +import edu.wpi.first.wpilibj.simulation.BatterySim +import edu.wpi.first.wpilibj.simulation.RoboRioSim + +/** + * Used for simulating battery voltage and current based off drawn currents from other mechanisms + */ +class SimBattery { + private val currentDrawers = mutableListOf<() -> Double>() + + /** + * Register a simulated mechanism drawing current + */ + fun addCurrentDrawer(currentDrawer: () -> Double) { + currentDrawers.add(currentDrawer) + } + + /** + * Update the simulation with a newly calculated battery current and voltage + */ + fun update() { + val currents = currentDrawers.map { it() } + RoboRioSim.setVInCurrent(currents.sum()) + RoboRioSim.setVInVoltage(BatterySim.calculateDefaultBatteryLoadedVoltage(*currents.toDoubleArray())) + } +} diff --git a/src/main/kotlin/frc/team449/system/SparkUtil.kt b/src/main/kotlin/frc/team449/system/SparkUtil.kt new file mode 100644 index 0000000..b62928d --- /dev/null +++ b/src/main/kotlin/frc/team449/system/SparkUtil.kt @@ -0,0 +1,79 @@ +package frc.team449.system + +import com.revrobotics.* +import edu.wpi.first.wpilibj.RobotController + +object SparkUtil { + fun applySparkSettings( + + // spark max information + sparkMax: CANSparkMax, + enableBrakeMode: Boolean = true, + inverted: Boolean = false, + currentLimit: Int = 0, + enableVoltageComp: Boolean = false, + slaveSparks: Map = mapOf(), + controlFrameRateMillis: Int = -1, + statusFrameRatesMillis: Map = mapOf(), + + // encoder information + encoder: MotorFeedbackSensor, + unitPerRotation: Double, + gearing: Double, + offset: Double = 0.0, + encInverted: Boolean = false + ) { + sparkMax.restoreFactoryDefaults() + sparkMax.idleMode = if (enableBrakeMode) CANSparkMax.IdleMode.kBrake else CANSparkMax.IdleMode.kCoast + sparkMax.inverted = inverted + if (currentLimit > 0) sparkMax.setSmartCurrentLimit(currentLimit) + if (enableVoltageComp) sparkMax.enableVoltageCompensation(RobotController.getBatteryVoltage()) else sparkMax.disableVoltageCompensation() + if (controlFrameRateMillis >= 1) sparkMax.setControlFramePeriodMs(controlFrameRateMillis) // Must be between 1 and 100 ms. + for ((statusFrame, period) in statusFrameRatesMillis) { + sparkMax.setPeriodicFramePeriod(statusFrame, period) + } + + for ((slavePort, slaveInverted) in slaveSparks) { + val slave = CANSparkMax(slavePort, CANSparkMaxLowLevel.MotorType.kBrushless) + slave.restoreFactoryDefaults() + slave.follow(sparkMax, slaveInverted) + slave.idleMode = sparkMax.idleMode + if (currentLimit > 0) slave.setSmartCurrentLimit(currentLimit) + slave.burnFlash() + } + + when (encoder) { + is SparkMaxAbsoluteEncoder -> { + encoder.positionConversionFactor = unitPerRotation * gearing + encoder.velocityConversionFactor = unitPerRotation * gearing / 60 + encoder.zeroOffset = offset + encoder.setInverted(encInverted) + } + + is SparkMaxRelativeEncoder -> { + encoder.positionConversionFactor = unitPerRotation * gearing + encoder.velocityConversionFactor = unitPerRotation * gearing / 60 + } + + is SparkMaxAlternateEncoder -> { + encoder.positionConversionFactor = unitPerRotation * gearing + encoder.velocityConversionFactor = unitPerRotation * gearing / 60 + encoder.setInverted(encInverted) + } + + else -> throw IllegalStateException("UNSUPPORTED ENCODER PLUGGED INTO SPARK MAX.") + } + + sparkMax.pidController.setFeedbackDevice(encoder) + + sparkMax.burnFlash() + } + + fun enableContinuousInput(sparkMax: CANSparkMax, min: Double, max: Double) { + val controller = sparkMax.pidController + + controller.setPositionPIDWrappingEnabled(true) + controller.setPositionPIDWrappingMinInput(min) + controller.setPositionPIDWrappingMaxInput(max) + } +} diff --git a/src/main/kotlin/frc/team449/system/encoder/AbsoluteEncoder.kt b/src/main/kotlin/frc/team449/system/encoder/AbsoluteEncoder.kt new file mode 100644 index 0000000..4016e90 --- /dev/null +++ b/src/main/kotlin/frc/team449/system/encoder/AbsoluteEncoder.kt @@ -0,0 +1,105 @@ +package frc.team449.system.encoder + +import edu.wpi.first.math.MathUtil +import edu.wpi.first.math.filter.MedianFilter +import edu.wpi.first.wpilibj.DutyCycleEncoder +import edu.wpi.first.wpilibj.Timer +import edu.wpi.first.wpilibj.motorcontrol.MotorController + +/** + * This class uses an absolute encoder, gear ratio and UPR to give the absolute position of the module or rotational velocity of the module. + * + * @param offset This must be in rotations of how much the offset of the ENCODER should be. + */ +open class AbsoluteEncoder( + name: String, + private val enc: DutyCycleEncoder, + unitPerRotation: Double, + private val inverted: Boolean, + private var offset: Double, + pollTime: Double = .02, + samplesPerAverage: Int = 1 +) : Encoder(name, 1, unitPerRotation, 1.0, pollTime) { + private var prevPos = Double.NaN + private var prevTime = Double.NaN + private val filter = MedianFilter(samplesPerAverage) + + private val frequency = enc.frequency + + /** This returns the absolute position of the module */ + override fun getPositionNative(): Double { + return if (inverted) { + filter.calculate( + MathUtil.inputModulus( + 1 - (enc.absolutePosition - offset), + -0.5, + 0.5 + ) + ) + } else { + filter.calculate( + MathUtil.inputModulus( + (enc.absolutePosition - offset), + -0.5, + 0.5 + ) + + ) + } + } + + override fun resetPosition(pos: Double) { + offset += getPositionNative() - pos + } + + /** This returns the rotational velocity (on vertical axis) of the module */ + override fun pollVelocityNative(): Double { + val currPos = + if (inverted) { + -enc.distance + } else { + enc.distance + } + + val currTime = Timer.getFPGATimestamp() + + val vel = + if (prevPos.isNaN()) { + 0.0 + } else { + val dt = currTime - prevTime + val dx = currPos - prevPos + dx / dt + } + this.prevPos = currPos + this.prevTime = currTime + + return vel + } + + companion object { + /** + * @param + * @param channel The DutyCycleEncoder port + * @param offset The position to put into DutyCycleEncoder's setPositionOffset + * @param unitPerRotation units measured when done one rotation (e.g 360 degrees per rotation) + * @param inverted If the encoder needs to be inverted or not + */ + fun creator( + channel: Int, + offset: Double, + unitPerRotation: Double, + inverted: Boolean + ): EncoderCreator = + EncoderCreator { name, _, _ -> + val enc = AbsoluteEncoder( + name, + DutyCycleEncoder(channel), + unitPerRotation, + inverted, + offset + ) + enc + } + } +} diff --git a/src/main/kotlin/frc/team449/system/encoder/BackupEncoder.kt b/src/main/kotlin/frc/team449/system/encoder/BackupEncoder.kt new file mode 100644 index 0000000..bd1d2e7 --- /dev/null +++ b/src/main/kotlin/frc/team449/system/encoder/BackupEncoder.kt @@ -0,0 +1,60 @@ +package frc.team449.system.encoder + +import edu.wpi.first.wpilibj.motorcontrol.MotorController +import kotlin.math.abs + +/** + * A wrapper to use when you have one external encoder that's more accurate but may be unplugged and + * an integrated encoder that's less accurate but is less likely to be unplugged. + * + *

If the primary encoder's velocity is 0 but the integrated encoder's is above a given + * threshold, it concludes that the primary encoder is broken and switches to using the + * fallback/integrated encoder. + */ +class BackupEncoder( + private val primary: Encoder, + private val fallback: Encoder, + private val velThreshold: Double, + pollTime: Double = .02 +) : Encoder(primary.name, 1, 1.0, 1.0, pollTime) { + + /** Whether the primary encoder's stopped working */ + private var useFallback = false + + override fun getPositionNative(): Double { + return if (useFallback) { + fallback.position + } else { + primary.position + } + } + + override fun pollVelocityNative(): Double { + val fallbackVel = fallback.velocity + return if (useFallback) { + fallbackVel + } else { + val primaryVel = primary.velocity + if (primaryVel == 0.0 && abs(fallbackVel) > velThreshold) { + this.useFallback = true + fallbackVel + } else { + primaryVel + } + } + } + + companion object { + fun creator( + primaryCreator: EncoderCreator, + fallbackCreator: EncoderCreator, + velThreshold: Double + ): EncoderCreator = EncoderCreator { name, motor, inverted -> + BackupEncoder( + primaryCreator.create("primary_$name", motor, inverted), + fallbackCreator.create("fallback_$name", motor, inverted), + velThreshold + ) + } + } +} diff --git a/src/main/kotlin/frc/team449/system/encoder/Encoder.kt b/src/main/kotlin/frc/team449/system/encoder/Encoder.kt new file mode 100644 index 0000000..25a95da --- /dev/null +++ b/src/main/kotlin/frc/team449/system/encoder/Encoder.kt @@ -0,0 +1,116 @@ +package frc.team449.system.encoder + +import edu.wpi.first.wpilibj.Timer + +/** + * A wrapper around encoders. Allows resetting encoders to a position. + * + *

Don't instantiate its subclasses directly. Instead, use their static creator methods + * @param encoderCPR Counts per rotation of the encoder + * @param unitPerRotation Meters traveled per rotation of the motor + * @param gearing The factor the output changes by after being measured by the encoder + * (should be >= 1, not a reciprocal), e.g. this would be 70 if there were + * a 70:1 gearing between the encoder and the final output + */ +abstract class Encoder( + val name: String, + encoderCPR: Int, + unitPerRotation: Double, + gearing: Double, + private val pollTime: Double +) { + /** + * Factor to multiply by to turn native encoder units into meters or whatever units are actually + * wanted + */ + private val encoderToUnit = unitPerRotation * gearing / encoderCPR + + /** An offset added to the position to allow resetting position. */ + private var positionOffset = 0.0 + + /** Whether this encoder is being simulated */ + private var simulated = false + + /** Simulated position set by SimEncoderController */ + private var simPos = 0.0 + + /** Simulated position set by SimEncoderController */ + private var simVel = 0.0 + + /** Used to cache the velocity, because we want to update only when dt >= 20ms **/ + private var cachedVel = Double.NaN + private var cachedTime = Double.NaN + + /** Current position in encoder's units */ + protected abstract fun getPositionNative(): Double + + /** Current velocity in encoder's units */ + protected abstract fun pollVelocityNative(): Double + + /** Position in meters or whatever unit you set */ + val position: Double + get() { + val posUnits = if (simulated) simPos else this.getPositionDirect() + return positionOffset + posUnits + } + + /** Velocity in meters per second or whatever unit you set */ + val velocity: Double + get() { + return if (simulated) simVel else getVelocityNative() * encoderToUnit + } + + /** + * Update the position offset to treat the current position as [pos] + */ + open fun resetPosition(pos: Double) { + this.positionOffset = pos - this.getPositionDirect() + } + + /** + * Get the position in units without adding [positionOffset] + */ + private fun getPositionDirect() = this.getPositionNative() * encoderToUnit + + /** + * Get the native velocity in units every loopTime + */ + private fun getVelocityNative(): Double { + val currTime = Timer.getFPGATimestamp() + // update if it has been at least 20 ms since the last update + if (cachedTime.isNaN() || currTime - cachedTime >= pollTime) { + cachedVel = this.pollVelocityNative() + cachedTime = currTime + } + return cachedVel + } + + /** + * Used to control [Encoder]s. Only one [SimController] can be used per encoder + * object. + * + * @param enc The encoder to control. + */ + class SimController(private val enc: Encoder) { + init { + if (enc.simulated) { + throw IllegalStateException("${enc.name} is already being simulated.") + } + enc.simulated = true + } + + /** Set the position of the [Encoder] this is controlling. */ + var position: Double + get() = enc.simPos + set(pos) { + enc.simPos = pos + } + + /** Set the velocity of the [Encoder] this is controlling. */ + var velocity: Double + get() = enc.simVel + set(vel) { + enc.simVel = vel + } + } +} diff --git a/src/main/kotlin/frc/team449/system/encoder/EncoderCreator.kt b/src/main/kotlin/frc/team449/system/encoder/EncoderCreator.kt new file mode 100644 index 0000000..95ec928 --- /dev/null +++ b/src/main/kotlin/frc/team449/system/encoder/EncoderCreator.kt @@ -0,0 +1,12 @@ +package frc.team449.system.encoder + +import edu.wpi.first.wpilibj.motorcontrol.MotorController + +/** + * Create an encoder given a motor controller and its configuration + * + * @param The type of the motor controller + */ +fun interface EncoderCreator { + fun create(encName: String, motor: M, inverted: Boolean): Encoder +} diff --git a/src/main/kotlin/frc/team449/system/encoder/NEOEncoder.kt b/src/main/kotlin/frc/team449/system/encoder/NEOEncoder.kt new file mode 100644 index 0000000..69e9579 --- /dev/null +++ b/src/main/kotlin/frc/team449/system/encoder/NEOEncoder.kt @@ -0,0 +1,33 @@ +package frc.team449.system.encoder + +import com.revrobotics.CANSparkMax +import com.revrobotics.RelativeEncoder + +/** A NEO integrated encoder plugged into a Spark */ +class NEOEncoder( + name: String, + private val enc: RelativeEncoder, + unitPerRotation: Double, + gearing: Double, + pollTime: Double = .02 +) : Encoder(name, NEO_ENCODER_CPR, 1.0, 1.0, pollTime) { + + init { + // Let the underlying encoder do the conversions + enc.positionConversionFactor = unitPerRotation * gearing + // Divide by 60 because it's originally in RPM + enc.velocityConversionFactor = unitPerRotation * gearing / 60 + } + + override fun getPositionNative() = enc.position + + override fun pollVelocityNative(): Double = enc.velocity + + companion object { + const val NEO_ENCODER_CPR = 1 + + fun creator(unitPerRotation: Double, gearing: Double): EncoderCreator = EncoderCreator { name, motor, _ -> + NEOEncoder(name, motor.encoder, unitPerRotation, gearing) + } + } +} diff --git a/src/main/kotlin/frc/team449/system/encoder/QuadEncoder.kt b/src/main/kotlin/frc/team449/system/encoder/QuadEncoder.kt new file mode 100644 index 0000000..5b53e82 --- /dev/null +++ b/src/main/kotlin/frc/team449/system/encoder/QuadEncoder.kt @@ -0,0 +1,37 @@ +package frc.team449.system.encoder + +import edu.wpi.first.wpilibj.motorcontrol.MotorController + +/** An external quadrature encoder */ +class QuadEncoder( + name: String, + private val encoder: edu.wpi.first.wpilibj.Encoder, + encoderCPR: Int, + unitPerRotation: Double, + gearing: Double, + pollTime: Double = .02 +) : Encoder(name, 1, 1.0, 1.0, pollTime) { + init { + // Let the WPI encoder handle the distance scaling + encoder.distancePerPulse = unitPerRotation * gearing / encoderCPR + encoder.samplesToAverage = 5 + } + + override fun getPositionNative() = encoder.distance + + override fun pollVelocityNative() = encoder.rate + + companion object { + fun creator( + encoder: edu.wpi.first.wpilibj.Encoder, + encoderCPR: Int, + unitPerRotation: Double, + gearing: Double, + inverted: Boolean + ): EncoderCreator = + EncoderCreator { name, _, _ -> + encoder.setReverseDirection(inverted) + QuadEncoder(name, encoder, encoderCPR, unitPerRotation, gearing) + } + } +} diff --git a/src/main/kotlin/frc/team449/system/encoder/TalonEncoder.kt b/src/main/kotlin/frc/team449/system/encoder/TalonEncoder.kt new file mode 100644 index 0000000..0e697d7 --- /dev/null +++ b/src/main/kotlin/frc/team449/system/encoder/TalonEncoder.kt @@ -0,0 +1,29 @@ +package frc.team449.system.encoder +// +// import com.ctre.phoenix.motorcontrol.can.BaseTalon +// import edu.wpi.first.wpilibj.motorcontrol.MotorController +// +// /** An encoder plugged into a TalonSRX */ +// class TalonEncoder( +// name: String, +// private val talon: BaseTalon, +// encoderCPR: Int, +// unitPerRotation: Double, +// gearing: Double, +// pollTime: Double = .02 +// ) : Encoder(name, encoderCPR * 4, unitPerRotation, gearing, pollTime) { +// +// override fun getPositionNative() = talon.getSelectedSensorPosition(0) +// +// override fun pollVelocityNative() = talon.getSelectedSensorVelocity(0) +// +// companion object { +// fun creator( +// encoderCPR: Int, +// unitPerRotation: Double, +// gearing: Double +// ): EncoderCreator where T : MotorController, T : BaseTalon = EncoderCreator { name, motor, _ -> +// TalonEncoder(name, motor, encoderCPR, unitPerRotation, gearing) +// } +// } +// } diff --git a/src/main/kotlin/frc/team449/system/motor/SparkMaxCreator.kt b/src/main/kotlin/frc/team449/system/motor/SparkMaxCreator.kt new file mode 100644 index 0000000..6cf7614 --- /dev/null +++ b/src/main/kotlin/frc/team449/system/motor/SparkMaxCreator.kt @@ -0,0 +1,127 @@ +package frc.team449.system.motor + +import com.revrobotics.CANSparkMax +import com.revrobotics.CANSparkMaxLowLevel +import com.revrobotics.REVLibError +import com.revrobotics.SparkMaxLimitSwitch +import edu.wpi.first.wpilibj.RobotController +import frc.team449.system.encoder.EncoderCreator + +/** + * Create a Spark Max with the given configurations + * + * @param name The motor's name + * @param id The motor's CAN ID + */ + +// TODO: Test if disabling voltage compensation helps reduce brownouts +fun createSparkMax( + name: String, + id: Int, + encCreator: EncoderCreator, + enableBrakeMode: Boolean = true, + inverted: Boolean = false, + currentLimit: Int = 0, + enableVoltageComp: Boolean = false, + slaveSparks: Map = mapOf(), + controlFrameRateMillis: Int = -1, + statusFrameRatesMillis: Map = mapOf() +): WrappedMotor { + val motor = CANSparkMax( + id, + CANSparkMaxLowLevel.MotorType.kBrushless + ) + if (motor.lastError != REVLibError.kOk) { + println( + "Motor could not be constructed on port " + + id + + " due to error " + + motor.lastError + ) + } + + motor.restoreFactoryDefaults() + + val enc = encCreator.create(name + "Enc", motor, inverted) + + val brakeMode = + if (enableBrakeMode) { + CANSparkMax.IdleMode.kBrake + } else { + CANSparkMax.IdleMode.kCoast + } + + motor.inverted = inverted + // Set brake mode + motor.idleMode = brakeMode + + // Set frame rates + if (controlFrameRateMillis >= 1) { + // Must be between 1 and 100 ms. + motor.setControlFramePeriodMs(controlFrameRateMillis) + } + + for ((statusFrame, period) in statusFrameRatesMillis) { + motor.setPeriodicFramePeriod(statusFrame, period) + } + + // Set the current limit if it was given + if (currentLimit > 0) { + motor.setSmartCurrentLimit(currentLimit) + } + + if (enableVoltageComp) { + motor.enableVoltageCompensation(RobotController.getBatteryVoltage()) + } else { + motor.disableVoltageCompensation() + } + + for ((slavePort, slaveInverted) in slaveSparks) { + val slave = createFollowerSpark(slavePort) + slave.restoreFactoryDefaults() + slave.follow(motor, slaveInverted) + slave.idleMode = brakeMode + if (currentLimit > 0) { + slave.setSmartCurrentLimit(currentLimit) + } + slave.burnFlash() + } + + motor.burnFlash() + + return WrappedMotor(motor, enc) +} + +/** + * Create a Spark that will follow another Spark + * + * @param port The follower's CAN ID + */ +private fun createFollowerSpark(port: Int): CANSparkMax { + val follower = CANSparkMax( + port, + CANSparkMaxLowLevel.MotorType.kBrushless + ) + + follower + .getForwardLimitSwitch(SparkMaxLimitSwitch.Type.kNormallyOpen) + .enableLimitSwitch(false) + follower + .getReverseLimitSwitch(SparkMaxLimitSwitch.Type.kNormallyOpen) + .enableLimitSwitch(false) + + follower.setPeriodicFramePeriod( + CANSparkMaxLowLevel.PeriodicFrame.kStatus0, + 100 + ) + follower.setPeriodicFramePeriod( + CANSparkMaxLowLevel.PeriodicFrame.kStatus1, + 100 + ) + follower.setPeriodicFramePeriod( + CANSparkMaxLowLevel.PeriodicFrame.kStatus2, + 100 + ) + + return follower +} diff --git a/src/main/kotlin/frc/team449/system/motor/TalonCreator.kt b/src/main/kotlin/frc/team449/system/motor/TalonCreator.kt new file mode 100644 index 0000000..4a58f9a --- /dev/null +++ b/src/main/kotlin/frc/team449/system/motor/TalonCreator.kt @@ -0,0 +1,254 @@ +package frc.team449.system.motor +// +// import com.ctre.phoenix.motorcontrol.* +// import com.ctre.phoenix.motorcontrol.can.BaseTalon +// import com.ctre.phoenix.motorcontrol.can.VictorSPX +// import com.ctre.phoenix.sensors.SensorVelocityMeasPeriod +// import edu.wpi.first.wpilibj.motorcontrol.MotorController +// import frc.team449.system.encoder.EncoderCreator +// +// /** Wrap a TalonSRX or TalonFX in a WrappedMotor object +// * @see configureSlaveTalon +// * @see createSlaveVictor +// */ +// fun createTalon( +// name: String, +// motor: T, +// encCreator: EncoderCreator, +// enableBrakeMode: Boolean = true, +// inverted: Boolean = false, +// currentLimit: Int = 0, +// enableVoltageComp: Boolean = true, +// voltageCompSamples: Int = 32, +// slaveTalons: List = listOf(), +// slaveVictors: List = listOf(), +// reverseSensor: Boolean = false, +// controlFrameRatesMillis: Map = mapOf(), +// statusFrameRatesMillis: Map = mapOf(), +// feedbackDevice: FeedbackDevice? = null +// ): WrappedMotor where T : MotorController, T : BaseTalon { +// val enc = encCreator.create(name + "Enc", motor, inverted) +// motor.setInverted(inverted) +// // Set brake mode +// val idleMode = if (enableBrakeMode) NeutralMode.Brake else NeutralMode.Coast +// motor.setNeutralMode(idleMode) +// for ((frame, period) in controlFrameRatesMillis) { +// motor.setControlFramePeriod(frame, period) +// } +// for ((frame, period) in statusFrameRatesMillis) { +// motor.setStatusFramePeriod(frame, period) +// } +// +// // Setup feedback device if it exists +// if (feedbackDevice != null) { +// // CTRE encoder use RPM instead of native units, and can be used as +// // QuadEncoders, so we switch +// // them to avoid having to support RPM. +// if (feedbackDevice == FeedbackDevice.CTRE_MagEncoder_Absolute || +// feedbackDevice == FeedbackDevice.CTRE_MagEncoder_Relative +// ) { +// motor.configSelectedFeedbackSensor(FeedbackDevice.QuadEncoder, 0, 0) +// } else { +// motor.configSelectedFeedbackSensor(feedbackDevice, 0, 0) +// } +// motor.setSensorPhase(reverseSensor) +// } else { +// motor.configSelectedFeedbackSensor(FeedbackDevice.None, 0, 0) +// } +// +// // Set the current limit if it was given +// if (currentLimit > 0) { +// motor.configSupplyCurrentLimit( +// SupplyCurrentLimitConfiguration(true, currentLimit.toDouble(), 0.0, 0.0), +// 0 +// ) +// } else { +// // If we don't have a current limit, disable current limiting. +// motor.configSupplyCurrentLimit(SupplyCurrentLimitConfiguration(), 0) +// } +// +// // Enable or disable voltage comp +// if (enableVoltageComp) { +// motor.enableVoltageCompensation(true) +// motor.configVoltageCompSaturation(12.0, 0) +// } +// motor.configVoltageMeasurementFilter(voltageCompSamples, 0) +// +// // Use slot 0 +// motor.selectProfileSlot(0, 0) +// val port = motor.deviceID +// // Set up slaves. +// for (slave in slaveTalons) { +// setMasterForTalon( +// slave, +// port, +// enableBrakeMode, +// currentLimit, +// if (enableVoltageComp) voltageCompSamples else null +// ) +// } +// for (slave in slaveVictors) { +// setMasterForVictor( +// slave, +// motor, +// enableBrakeMode, +// if (enableVoltageComp) voltageCompSamples else null +// ) +// } +// motor.configVelocityMeasurementPeriod(SensorVelocityMeasPeriod.Period_10Ms) +// motor.configVelocityMeasurementWindow(10) +// +// // Set max voltage +// motor.configPeakOutputForward(1.0, 0) +// motor.configPeakOutputReverse(1.0, 0) +// +// motor.configNominalOutputForward(0.0, 0) +// motor.configNominalOutputReverse(0.0, 0) +// +// return WrappedMotor(name, motor, enc) +// } +// +// /** @param slaveTalon Takes a slave TalonSRX or TalonFX and configures it to act as a slave +// * @return The same Talon +// */ +// fun configureSlaveTalon( +// slaveTalon: BaseTalon, +// invertType: InvertType +// ): BaseTalon { +// // Turn off features we don't want a slave to have +// slaveTalon.setInverted(invertType) +// slaveTalon.configForwardLimitSwitchSource( +// LimitSwitchSource.Deactivated, +// LimitSwitchNormal.Disabled, +// 0 +// ) +// slaveTalon.configReverseLimitSwitchSource( +// LimitSwitchSource.Deactivated, +// LimitSwitchNormal.Disabled, +// 0 +// ) +// slaveTalon.configForwardSoftLimitEnable(false, 0) +// slaveTalon.configReverseSoftLimitEnable(false, 0) +// slaveTalon.configPeakOutputForward(1.0, 0) +// slaveTalon.enableVoltageCompensation(true) +// slaveTalon.configVoltageCompSaturation(12.0, 0) +// slaveTalon.configVoltageMeasurementFilter(32, 0) +// +// // Slow down frames so we don't overload the CAN bus +// slaveTalon.setStatusFramePeriod(StatusFrameEnhanced.Status_1_General, 100, 0) +// slaveTalon.setStatusFramePeriod(StatusFrameEnhanced.Status_6_Misc, 100, 0) +// slaveTalon.setStatusFramePeriod(StatusFrameEnhanced.Status_7_CommStatus, 100, 0) +// slaveTalon.setStatusFramePeriod(StatusFrameEnhanced.Status_9_MotProfBuffer, 100, 0) +// slaveTalon.setStatusFramePeriod(StatusFrameEnhanced.Status_10_MotionMagic, 100, 0) +// slaveTalon.setStatusFramePeriod(StatusFrameEnhanced.Status_12_Feedback1, 100, 0) +// slaveTalon.setStatusFramePeriod(StatusFrameEnhanced.Status_13_Base_PIDF0, 100, 0) +// slaveTalon.setStatusFramePeriod(StatusFrameEnhanced.Status_14_Turn_PIDF1, 100, 0) +// slaveTalon.setStatusFramePeriod(StatusFrameEnhanced.Status_15_FirmwareApiStatus, 100, 0) +// slaveTalon.setStatusFramePeriod(StatusFrameEnhanced.Status_3_Quadrature, 100, 0) +// slaveTalon.setStatusFramePeriod(StatusFrameEnhanced.Status_8_PulseWidth, 100, 0) +// slaveTalon.setStatusFramePeriod(StatusFrameEnhanced.Status_11_UartGadgeteer, 100, 0) +// +// return slaveTalon +// } +// +// /** +// * Creates a VictorSPX that will follow some Talon +// * +// * @param port The CAN ID of this Victor SPX. +// * @param invertType Whether to invert this relative to the master. Defaults to not inverting +// * relative to master. +// */ +// fun createSlaveVictor(port: Int, invertType: InvertType): VictorSPX { +// val victorSPX = VictorSPX(port) +// victorSPX.setInverted(invertType) +// victorSPX.configPeakOutputForward(1.0, 0) +// victorSPX.configPeakOutputReverse(-1.0, 0) +// victorSPX.enableVoltageCompensation(true) +// victorSPX.configVoltageCompSaturation(12.0, 0) +// victorSPX.configVoltageMeasurementFilter(32, 0) +// victorSPX.setStatusFramePeriod(StatusFrame.Status_1_General, 100, 0) +// victorSPX.setStatusFramePeriod(StatusFrame.Status_2_Feedback0, 100, 0) +// victorSPX.setStatusFramePeriod(StatusFrame.Status_6_Misc, 100, 0) +// victorSPX.setStatusFramePeriod(StatusFrame.Status_7_CommStatus, 100, 0) +// victorSPX.setStatusFramePeriod(StatusFrame.Status_9_MotProfBuffer, 100, 0) +// victorSPX.setStatusFramePeriod(StatusFrame.Status_10_MotionMagic, 100, 0) +// victorSPX.setStatusFramePeriod(StatusFrame.Status_12_Feedback1, 100, 0) +// victorSPX.setStatusFramePeriod(StatusFrame.Status_13_Base_PIDF0, 100, 0) +// victorSPX.setStatusFramePeriod(StatusFrame.Status_14_Turn_PIDF1, 100, 0) +// +// return victorSPX +// } +// +// /** +// * Set this Talon to follow another CAN device. +// * +// * @param port The CAN ID of the device to follow. +// * @param brakeMode Whether this Talon should be in brake mode or coast mode. +// * @param currentLimit The current limit for this Talon. Can be null for no current limit. +// * @param voltageCompSamples The number of voltage compensation samples to use, or null to not +// * compensate voltage. +// */ +// private fun setMasterForTalon( +// slaveTalon: BaseTalon, +// port: Int, +// brakeMode: Boolean, +// currentLimit: Int, +// voltageCompSamples: Int? +// ) { +// // Brake mode doesn't automatically follow master +// slaveTalon.setNeutralMode(if (brakeMode) NeutralMode.Brake else NeutralMode.Coast) +// +// // Current limiting might not automatically follow master, set it just to be +// // safe +// if (currentLimit > 0) { +// slaveTalon.configSupplyCurrentLimit( +// SupplyCurrentLimitConfiguration(true, currentLimit.toDouble(), 0.0, 0.0), +// 0 +// ) +// } else { +// // If we don't have a current limit, disable current limiting. +// slaveTalon.configSupplyCurrentLimit(SupplyCurrentLimitConfiguration(), 0) +// } +// +// // Voltage comp might not follow master either +// if (voltageCompSamples != null) { +// slaveTalon.enableVoltageCompensation(true) +// slaveTalon.configVoltageCompSaturation(12.0, 0) +// slaveTalon.configVoltageMeasurementFilter(voltageCompSamples, 0) +// } else { +// slaveTalon.enableVoltageCompensation(false) +// } +// +// // Follow the leader +// slaveTalon[ControlMode.Follower] = port.toDouble() +// } +// +// /** +// * Set this Victor to follow another CAN device. +// * +// * @param toFollow The motor controller to follow. +// * @param brakeMode Whether this Talon should be in brake mode or coast mode. +// * @param voltageCompSamples The number of voltage compensation samples to use, or null to not +// * compensate voltage. +// */ +// private fun setMasterForVictor( +// victorSPX: VictorSPX, +// toFollow: IMotorController, +// brakeMode: Boolean, +// voltageCompSamples: Int? +// ) { +// // Brake mode doesn't automatically follow master +// victorSPX.setNeutralMode(if (brakeMode) NeutralMode.Brake else NeutralMode.Coast) +// +// // Voltage comp might not follow master either +// if (voltageCompSamples != null) { +// victorSPX.enableVoltageCompensation(true) +// victorSPX.configVoltageCompSaturation(12.0, 0) +// victorSPX.configVoltageMeasurementFilter(voltageCompSamples, 0) +// } else { +// victorSPX.enableVoltageCompensation(false) +// } +// +// // Follow the leader +// victorSPX.follow(toFollow) +// } diff --git a/src/main/kotlin/frc/team449/system/motor/WrappedMotor.kt b/src/main/kotlin/frc/team449/system/motor/WrappedMotor.kt new file mode 100644 index 0000000..8301988 --- /dev/null +++ b/src/main/kotlin/frc/team449/system/motor/WrappedMotor.kt @@ -0,0 +1,35 @@ +package frc.team449.system.motor + +import edu.wpi.first.wpilibj.RobotController +import edu.wpi.first.wpilibj.motorcontrol.MotorController +import frc.team449.system.encoder.Encoder + +/** Our own wrapper grouping the motor controller and encoder for a motor */ +class WrappedMotor( + private val motor: MotorController, + val encoder: Encoder +) : MotorController by motor { + /** + * The last set voltage for this motor (through [setVoltage] or [set]) + */ + var lastVoltage = 0.0 + private set + + /** Position in meters or whatever unit you set */ + val position: Double + get() = encoder.position + + /** Velocity in meters per second or whatever unit you set */ + val velocity: Double + get() = encoder.velocity + + override fun setVoltage(volts: Double) { + motor.setVoltage(volts) + this.lastVoltage = volts + } + + override fun set(output: Double) { + motor.set(output) + this.lastVoltage = output * RobotController.getBatteryVoltage() + } +} diff --git a/src/main/kotlin/frc/team449/util/Properties.kt b/src/main/kotlin/frc/team449/util/Properties.kt new file mode 100644 index 0000000..577a5c2 --- /dev/null +++ b/src/main/kotlin/frc/team449/util/Properties.kt @@ -0,0 +1,37 @@ +package frc.team449.util + +import edu.wpi.first.hal.SimBoolean +import edu.wpi.first.hal.SimDouble +import kotlin.properties.ReadOnlyProperty +import kotlin.properties.ReadWriteProperty +import kotlin.reflect.KProperty + +/** A property with a custom getter but a backing field of a different type + * @tparam B The type of the actual backing field + * @tparam F The type of the property that is delegated + */ +fun wrappedProp(backing: B, get: (B) -> F): ReadOnlyProperty { + return object : ReadOnlyProperty { + override operator fun getValue(thisRef: Any?, property: KProperty<*>) = get(backing) + } +} + +/** A property with a custom getter and setter but a backing field of a different type + * @tparam B The type of the actual backing field + * @tparam F The type of the property that is delegated + * @see simDoubleProp + * @see simBooleanProp + */ +fun wrappedProp(backing: B, get: (B) -> F, set: (B, F) -> Unit): ReadWriteProperty { + return object : ReadWriteProperty { + override operator fun getValue(thisRef: Any?, property: KProperty<*>) = get(backing) + + override operator fun setValue(thisRef: Any?, property: KProperty<*>, value: F) = set(backing, value) + } +} + +/** A delegated property of type Double backed by a [SimDouble] */ +fun simDoubleProp(sim: SimDouble): ReadWriteProperty = wrappedProp(sim, SimDouble::get, SimDouble::set) + +/** A delegated property of type Boolean backed by a [SimBoolean] */ +fun simBooleanProp(sim: SimBoolean): ReadWriteProperty = wrappedProp(sim, SimBoolean::get, SimBoolean::set) diff --git a/src/main/resources/2023-field.png b/src/main/resources/2023-field.png new file mode 100644 index 0000000000000000000000000000000000000000..51cc6a366390ed52346803b4e93e3d85138b84af GIT binary patch literal 950257 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�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�hE90(a^Rf7 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

$9dVR{Mhvyfft2?|?;{$nObcwZ}3xR%=Ja zcK$^+E{(%k^<3adI3wo4xDmNIQ2ATar!n;h<6-6GcW6ne_0&AYI_veyzn)Utv*s>d z8ySjq`-5MCnaS=u!T$LJLdPEX;GbSkp)y@yoYG{7}jniJk>t;!E`G*O!zJxP8`9^|K?LIuE}YXvW3KgdeFxDFR)3kV4rQ%A=!~|NKESmoI0;MqiTkjs zh-{HdqS!YH1GviOgkke%e*kg0I?kV~&$6gd!y|Uy3~Dl|H?@QfVgy21K?i+MN>?Z| zFf8KJJc0kcBo7y}zd}n3bW^>H7v$vLakcrnYpW)fnx2-~LurqavbsJdPPw)FxfSL* zs5nJdUll@M3TB{QP$7X;*0_Pw*RUcJojf0+fw9%N?oVzNGdvdmD*iYw+y(cJb&9jQ z>!;J5Ppg_A!{RB0*EP6!J?AG5vWf4BynYu=JSE?G+7bYP67Esl;34a0mvGi+tTa@2 z$@3g{an>Pkk1~L!QMKw^kGSA14?rr*{EP->26*btTUNiZ37bBYsn$Z8CcYmeD2>=i|lxyYFZ^O}PM8sfeql zbs>b<_pSxCJpf5E-kl9pT|k&#<~F8S2A8vo@{q&3PqBXCgfrT0a!FnD{E$DI?5h22 zmsi*jtq}L*HpaLOvI0^$Xnn+WHeyc}$@6e_fk97Dv1x6Su5DwfS_`K*pXI@YVTY^2 zkGijdrkDf*7uFc4*fT)qTivvMS6BypO01 zp8Pm))m-JHF#>GT3k*C^SFypMJ{>)Cq&&7D;mM^AewlcbTKT{i9#Uw7uzFH3u?xu4 z{uUe75hCCn1+1sAG#vrKYOXEs5W;SEfAV~0LgSQNN^gpKUP@D_sWKl_kN8>Wxo8~A zkNl_$rD>L30?m~ie-{fXJq4m}4fP_GU@jKEwUDGe&B|iBq0_Z{ z_H6I3vF`;uEn&|QJx$Y9tzl}UJ&J!VH@Og;yXG8r+N`Zw19$Rgc2sn0?UNG)O~09{ z|8b!2)kMlG|KWSRm{|;TFg`&K=TDC!06OpCFqjK4jhnhpzXP}KlIkGN153(p&kE~7 zFy{E-oI3g)Qp?DH`%+T*F2Z;P(q+A=S>?*cW?lH-8dyw!(l4Wd`o}TFwHEhwN({8D z8xe1v5nyUNGsp8yup_G|D2y5{H@q$?7&gy!Pf_!lJu3emF0<-m=_DmT$U5tlh1ga> zg1!B(_2+i*9~G7{6~QUqs>F~4v_O^(5c-_epX|kPQLFy&U$pZ~WtnL;twL2!t9Mwg zQeH}3YvgXFq_Dok-TJ80Y=$a2IW^;(n!oL{cR91#u#qI*wbx_ixe4Ue9P7padySph z*Fy!l2|gP+B8+qM}fOtyYM6i=!_qx9%-5iHHpty&N_>`m&=R@%7}}&$~wAr@YUfHEM|G8Et$% ztzQ4@0UzdoxeSLHRj*}_EB+r%=NZ-18f|Sg0xBgcN(&H>Bj}MPNEL#Jz(IkiNbkLc z-U1|Gj1Z76N{0vtNRtwJ3B5@NfzW$z2{nXvbHDN3Ul|!A*<=6N@7imvXU_TDfZT3V zUtxzc@jW-JKb!EY-)mnrC_C_|uinzCFF)fGGCV}-;P+8+g}$m!W__V=bQ=mEKGCf` z%Gs1!%ipbB>)w^x4BM65+>bCkJZX1|#1pEtO`WHHir`Omuz|~%#DT`iPc8@)R<1i!JsQNv)&{11o$ftX;VJy6TYM6Eg6)!z-vFqf&aE;66 z2woPdM#ltC{#Xn+$%*3(=_D`%8L~l!GWr#NKzfrOFK2-}tpM^12F<&3<(vN76gI-8 z{O=>Gf~(zX`&DaAo9g8Ar{`6soe%E@_?BGwH^igKH-!UYTv=~vGDTX<wRv&1_Tw!YUvoNROz77ex!U}7lMTb$t$tpKE`el{N{jkhat8@_ z)&bp!>zF1QNTXEg`Blhd(^&=ThV<=@G)CvfHlSz^bfNU>6+P-!2}|gaqBOOLP`Uup zYhqPb>0pQ^?p9xPC=l@i`w1J0xyjsjJFuKkp07Ud`eCxd$*0J`m1&>kr<1pG`iL@y$ARH%sNNy>&Y`3G z$*^nm#*`Q-klAFcXtpJOj#`+4gtmrMg`*Y6Xpux7Q7XVA$p#ZZT%l)xn-P|1d{I;w zqySXn>=x@YnL}+RQYIm&lx_4{%Nse71jy0gauv>l79OhC+Edb75_W0UVhci{@!NC< zEmG`fC^`sbEnkW(j71AMnykeq$3yz?V3=YhW%F&z*+pk{!9c2RlR#8Y`;i($T`NINRw! zG8Upp>g%3m=|K~w5l3dALmojZB;=^+SQD+i-iotFj4&R0TExM8y6s6hp~>3RGE|7n z-*M6Ids7VG_Q`3&yUuL2v1*{i5^#!$3fAr1+uM`K_@$Sr5-~z{V}53Sc0E-#??cY= z>PCu|=8$&Br3r9pWn*Oc^2b9~qk?|h-tVJ$yhRvqrDld3!Gj zFKNr$X?i~(mCGo<3TM9x^;V_!VHdAMd3c?3FZ{Z1i<|1i%?I&ZW+dg5p_&#SkCva;iA;69UO;JMRg;5QvHQEFFGQDj)8 z0g|$BIW{Z{*dIMVSY9clKtJ~c7b>hRiZqNq$0G7Zz=)sPy8&xrq>tr`7kTjfR3&9b$-U)Q5v z*wZ;M^qcC7!e^XcV{0Fj{B|wFdRnZk&M-U9I@{5j_FMYMbZMEGxKg+HP?_wLH{HX- zWe*A_t`S*^Nb!%FPz9?*{vd zsXJ+h>3y=t5)tgDpZHBnsF=`1p7BT>M-!h~;Y{NQ*N2&Ky9HER<{3lC^i`IIH@m5> zTUQSFxybEk4Nlh|eo?pF9*{2B!y^wLYQCxppj`>>{j7*sNRJs)pW-?{icP_7)9$%7 z^i-0UXav+;Y)X*}P5v)=A*9<8+gL%@fL3UGsKD(aC%4Mg&jFhJX=(AyyN_vhuUiSY zalgY!%GzMY_0K9p=@8a0QL60)*wC-p6>$6_Gs_H2xG3%O2!TWAhs27FAIS2lL~8~$ z@Uwbq^z+XzwCkx+Ej1qPvfm^9blNi0biH@b9I^+r%PU4dn?EVok%?N`vKyWeE0Ip? zY|A8RQ{E`PeYSnJ@880Q*|^c1G6pm>G&`Y~sVTYp_ug)~(nhFn<#boj<_dWQ`V8v>E3oxNWd;sKa31a`$PcySq_tDW$a4=|KF(bJ!5=J1+Zh`e4%>(cpSTE0}hx{O(1SD**UDcJnN6&dc3Cq@$83A0uwYA=5 zXnEj#OLmc&j^>}LwFPlG(ZY|J8fi`GgiN>uyK9VPYSuE9RGmZH%f%6JXH9_kfU{5P z+%gl?0X|TDPqD$gkq*!h-6CL7lGXN-mnpHoGeech9>iT!U?^A-#Re%c2fvK3%XFkV zvj`&=#4Di0OW*u%zTVi9di$b3dfPF zgQa;X(KNA(EXG^u^!%H16W%Y|`?RRMAsS(^qelm7mQ3iJD2dYG+u~`FoF_kPAa%K0 zUObig#Gu!id>QPtYCOtIwgLH4io3rOio0dyMyWfs6>+&O#a23S=@cp|&G-q-w5+O0 zanwTmH15g5%ixCr6Bi+nNhWTm13SyfGrAUpGRx$aV`s5xaUg-z^3@WRW&QvIf!lz& zH-o9ZhFgs;!=l+ zG)Sv;%TU2sP%9La!3aE!Uhb&CuIon%x@?`oT=r8_c+lW7Dx1PI+l4VNajw1=<>lEU zGTJ5o^b?)%1y8rEw~!QZKmyqx&eL#6dj1M#f+)+3w|w}ZSMW6> z=HGui$9|bBJtO^G^g3|~$T}HUI@tI;Tz>W`?4Ye4H&VJoU;bS;w@~J%-9OoH%aj#E zYR7lhuWV=+u^c+Q+2xNLDG)T~>P={@&)AxNgoDJX{4M&3^KW|}q|+%`0^0^a=nJ8E@&d2(EhO}Ffi{Px@K2ql=m zi`K8Mh-w4v$-D2g4L?W--Jxl|Q~oUIZ$*(xVZOrO%HdUqwv%{=wx3;;gPHM(a)+!6 z1SN4a@FELxzUPSCI}AQQaI5RROIgcznc5p>1eH549{XL4NO|s_105!~h9$NuYCVUY zhP_&PD>o+`o&Wag8s}6?P5ta}uF-~?_|}_Lof*`-og5m-p2!MSTjj+;)AE+%jel#$ zo8%n}Xbjba2@mE?A?m%C`pb(|U4+(0-#FGB{~Z!eEq_oSt7Gjw@~7;#-*djjh9M6A z2Xo@2IeuV`gSJiZsHd$3uko9q8asWPq&V9wM}3u~WcbHje(qASvIo@qiIbcDZf|C7 zub~4h{Iiu+S?af*wNroa0gLy8H>M}~S_KM8A3sALFM+jjd+ZO-Eged1OyF_Oa)C+w z*z+H>2Z;qAX78OKD*vovv;LXoJbAw=yU<0`5IA#r*B7etPfpKQRowS)V!CPh@H_-$~-?jQ)O6SufZZ9x}bW_=cavzwsw8|H1$3 zG;REQ+uu>{-~6GY>F*PGTWrP7__p2T%xkB~$zO%m=1$Yo*{mkx`MF~SLkVvE8>LTX zhA`OjUj=c;{&l;zu1{=5*7)3=UuwMCdb3qik|C*H?TaLhLH$*n59>_weXm#=66%?( z;?ne%jr!r8oxhc#9e!KS@6Vua#i^b`Kb}JM+^`F?QD&l-yL52QZbUgC1ptW*1(TOg zc2d=;pkTNQzDi#Y)1lVV;^Hm<>Sx_emD-(_5>fDOeu}qEmQDo<7nv}TGRHOc;NB&@ zr`jeaA-((eWhhftG;c&F2IkQ+y$<0)f2TOK#diahn;pIc-Lnh*6?&L(eDCk6V`hyb zb%ZF4RN;G_HcV_*{gb9Wckah`d_$R%k&qnzW=lgljOH+B6!OO$(&emHlp|AkRi zeJI@y3)5;5YYQg7IQr^Sz?Y*?%wXn(!d@E<`$F@ZJ1S3GdEzBmeLBA|#Ss(WKL)b& z%(xa7BACwa#df~DSD^Ej577T*>Xp$K0GXjLCjCnKKyh<4y#hYb=?P20kLJ!tY?}Ya z0zfJ7p0s1Ky`iAsJg!wCuGR6V>4%0wtL(+wUjr)fpFT?qa#O+uG2~lJvT<5xA0PeL zj?r|z>%|D3?9_*J#h$!U@KFv0B5!a@h6dF&D#b(KEKiQ?V+{|8ci1P$xAeij{N9sb zK}li=m*A5ASFqI}4Osoj#(=mXv6qF$z``U39VOo_b5a~IOap=halbix6&ZkI{C$X0 z1u1mhJetRuq9VB6cmP0O_`Uu(Kr8?au@Ils`H{pBkO4&9L`6AOFgj6NsCc%b6Z50T zuozqhOT*(*-}8_&#e0{Xx9RZjcns5f?+SMF;`N#s_-hI>smHsSIfh(p%|=#(9kA0< z2zfwW@=%DiAn`Q5_*EQUkdC)aAs0NGP$F zHU9K#%%6U)Y+e9#XbuJV9&Z`jHU2NVP<1P=Gm5@s}Hj+dU!7KJH*0mseI-u;mMkuu(bDZDpiolDYkFqRzdLE_ z0H~m7F2K2&tpkB01!)*a*OJ^c<)L2U!gk-MR+*=cg+tI|f)>sT=}E~EgT)2_UMeQ? z%c&PLA&RWfF%ebUHTEk1ljiq2#--uicI5U%xn)kp_DrTwINfoaF5=Io!w@^E((FuJ>D?S2}e#dWTuB7Jq%X4)C$-ZdiG|4%Yo{cl6W4 zYx3u$*GN#*T0+Zj9fKUlk=#YkEboMzpWjZG-lXO%-Agk`5NdFlx#S?-0~Fa4IaH}Z zYYV(I$#ie2A6;F&Z{7cJz22J@H2uT)dL3Rb>sh11C2L&xjY(^H-}v8#z^}62b#J+z zLp@`G3YW{if4CsZN|@A4t>EzCX!Fc(sfHQ6Ew{ewzRepNT%?W^b=THyP5<`Qe|KPL zyBAVX!(NhoV|S&j3t2aWY%JC2-Rbk`IcG<8Bs!qq>z5yF7@m4Amv>97{LS%d8wopX zvVFH*ct}1(tbHAO_~7ZT8bFhuVMd0{cL~GHfQu#xu)_8}Qk~^@03zydTfxhvU9@<$ zCe&EZ)n)#tbv~hFaXL906Pd>YN5n}dHWq;^{>SuzbzV?bg(D!b$tTLG{KnY}!GML* zP)veP#=ILYxHulXo6JrM1tfpIA+9!*!OyQb@$>eqG{nc~PIIYuzO@hE%c25{qg5+F~2*_gNJ3>pnHCEouE8>q7U9G-|c4A9t*7{zSEW zSFk91trDT7IQXBnEvo~W_#d)4h~?#FdqT1K4hYz?|ETzlgq3KUn2%&V zy*R6<@HZprLebKfjbE+{R~gyqza$n)|Lmnn36tA1b9+~Lt;6{9BEa(2^;;a&QmAu- z2k?%^tmB|0NRHJz?%s19!FOzP9vP-OW`rwTkcu9cFSKWEx^ZMQq(VdZsbm-iGBL;V zM)5NvkrYZL0Rj|TRTRi&>*DfXo>1n}0T5{_4B@`Ss_?k32f}us6*3H*br0c2l7k?! zFxDk1{8ljkNja^l5xSKeCCGdBQ|jn4^*bykz%XRu;a7Dqf~dI#n~5et-AY7M?z=(#|1bjpC#J?NHV~1 zr>WTKg=UF$m0&2BX*9311)s31P{3BALfLqrjOL(nJ9WYdaV7OfO89U;;$FWnaqAYU ztd4rU=hg)dAk0IAyJm&q6R0tvTes@!48!O2A{&=Eug(KH9wTTOVSFK8WSeBKGqh^J z04gf7?V7O6i?}L10|py92DoISE!P8+ium0er450ElI9I$QU>GvZB5Rx~HfhORxZyVxv8*Lc*p{=BwJ1J2oH%f&%Qh zIT~_9eW6Tmyt3H*l(TfL)M|E-Y;M|~ePUMfRe+z1C-QkQkw$?CW*8lOSX6PH&i9~E z%9uEpPRHWCZpl?TWrp<Ml3A%>=ACE!oq@o zz0kDl`1ElDQSZ9A)W8^gl04LD6aQfne=D~{ZE)qs%k&=^gT+ZoiZoMm4af!a%TzKs zw)*$ZQrFcDJqN>Ms){MH0JOA!@4AGf*JCf26u4|7?U?h|m+ok{7NUuVGuH0E6nG;y z;S_rjaoN?+xVA{$$=!68Yl8C)EnHO1w+sE5H zy2e>G@uu&)M|;1FXg|4ot46@kL1~bTc|lTu2!}%Bwi>#+5=1zM#pzi#>cT{Z2d1tu zE@$6Z<&JFNmHAiJH@Z*y+rF$Buhr7=ff0=GHUG3N)DMb#()-#Ra&LjUeP`G~w z9_|#e`f=w4O#=rrdLRaIGg|pWHJhnrg7v+d_w?-z#^p8DABZMK$5aQpn;%|yzcjVU z)~Qv)s247*(@70Ruk(ZBY^`h5g6}8F(ZoEA+hzt9_{Re0#7M>bLR$GXHV)dyCVn_u zu>5Ro6!-R+p+}V5E9!2wrs4vb_Q&)b_cg69@0GX+L{-Yf6~~`?7#%Qr{Q7wE&);vg zOSX->wNS`x9eI-(cQMA#mC$I1g(qzDOHMHZ=`>}F@qr6htNp1Rp_1Cg`rgUzH<4w{ z6D{X>g=L+S^U6nUfnjGCn0+gQqap!bxnJI7=l=A}Q@NK~)SMCeuds|p zTifD?_hLGHs!?M!tk4++Qe%-6xkC-RNLY%J@lfl^yyjJH%;o zwYgV0^`YK@CHmoY;WtF}e)z%s^MFRBxQ9rcxdq_fy>!CI4l2#Z1lEU@{v%18LsXz4gK@7TURY zgI15Yp4od5tZo78oEN9b*Z9JNu3Ns7ycGU`RiDV?Zd?7(r9#0F(#r(-s3zR_tRV)6 zyy1TvNpuRd;WD}bBEQir?v+GEcPJ2>8il=kbQk%QsG9Ufo7AdDUz=>XCIxwkjmq(C zM6@EU(_Zse6c-vmDG80#$S@0oz<9!psijdI72v09JT;HecU09;0wDWFIr-L%0GEWW^~ZHOSVEC9GKubpBY1JQi?(*d3@4n zAHXn@Q|NeNl~{d6=g~lFcv6ReTm?Y3^@{NMRA?|U%4ot{T%iO2DV@6mE?og2sY<$m zhjhf^FwQYq*jLA;XsHI`RmdJ$X3T};O&-t$&^MafpQb+xt}J^ zb|yqoHH{ajAO?K#=Z=z_iI)d_7zpA>yl<8Kk-@u%ZlQFlQEA5FA#f|6tP0|qloC{3 z``8bGP14HjUD4mF2xJyN;+-JM1QVjD0OZneJMCw|ge~xGx35yk@W$Y-yMTn0cmqT31w`{eP5gEDVgs;-wkwR{#(aD4BP`(l{tM(Nj> zn)+hBKw-hbeCGbqJ$m60ivLPp5EU5NicLxyVF}GG&r%i=dP?)D*Lk67`bL?+=jmap znfBeP+C$QFlJi}j`D`}ydaD4P9(8#^JFw$?8JG+Ynf=dl;i}ORuN3>-Xg%ubrrh8Q zp&e(2U<+sUI~D`nyP3W4k8UcR8h6X`o^pD`-i|;p#FV^#0)8DHg{hMHL->rB?$19o zoQ7XvaPZ7uye!O~RoJly2Z{#UeJR_b+C?;0g+0B#NZZc3(=K57ll+qg?BprA;3f^~ zQ`l=L@U<#tv#+etXh1w`pfcg?5gT|HC|yjY?`t$l6HRJcMS2XH*^vDvys`BSYIwz zSgGT+om*M!#|%U?m|N>4>3BxPCg1A}r^0iCMAJ?UIe0A7Oe-LkiJNPx6^%Ld_KTa* z?EbqUj1bRArh+Y*@d@y?X=5DIdU|CaxX39mIe#xG@cq!DR+#58jqUn`hw~6k&TLVO zpN6);rNrw)4WC$sF8t~8vG|FoDnhjMJQQ=fbnN?Wp%$v3%s+`=`p&p(8M~ADZD*Y> zt-vnl915ulr8B8a0AYV5Y$H9Ik;JcE(bO3yUNvA=ej`D)`#cG!w86OX*R6C&yl*T< zb${*Di{qVVkjg#dUw4$5wcj>kF6%-uL+^4nK7|PnH>3sXFOQV(G~{XY>_}kh6a&k8 z&v6oLG1t<`sAZb<;?E?Jd042w;4Z}KJZE3aZWLxKN$Mp&Ik^eSd`b=v9drbmgX^9%6>^>XL;+kf5@NPWok z;P*yLOuFyhm7MkgiVTU9H6@n(zwACA*8~|iZfDrH0a;;RR49+1>ACYRU+WI~e(htJ zoYR+U!aGI@g|6vqAJv)kT?;;@V>2+er0xlBG0Ys#cM502ny*A=h;ivN%AKy z@;wu?VHGC!5U(5RqIQ-o3(vTbgbam2+JJ<9vSrCo6jzIC@U^yuXZ{D~V+czwL$i{f zV6G*7x>!jPTS=r#+>_Bk0ITuYL-0zz`P*-9x_{l#a!!j{j|`hs6r3h^V9&SAJKS$Z zoekL5lr>p~nug*Ng@yr9Rr(kLrdVkz+jf%1m@=2BF{u+;x&@fKUAxR~$^-itbxF3H z?Ag0A>;6TaN?_>6z+{T0n^3kTsKm9X@hg)@rsRqU{Zfs_7s1;qh&h7->J&{95%>R8 z)Fm10$YP!_u1Os^G(8a6{n*#iwec=Ow1APS{aah=UjWcC95EBw&E~)-*TGzI2k*|b zS{M0{YZ;49@eib$8l||scc!)>!qvX}I@3P0=l=={{_nJzU0gF$rM%(dGxt-pc`Wye z2$BUnIe=*5_p4}yhIm;BNG{NhRb1U$VuW?eKc#M_&KXQXrYVB`tx8ThSVK z@&#Ox+E{wtb*2iOynPW3gbmm{&v2w#^w6U9<{nbao@Rt0_Y)s(cH&GY@xel84kR0<%&(=j76;y z`g-~X%Tf^XdT;ZBadRf`GtXQ?|8Du64Sfk$lVB;HC)M?)2e0-Js!~U9fcUGv(hx9Hd)=T zN?jlNF^fygIx) z2(rae!^)EKYT{WRRh;;jkB&ZKx%If&ae66PA*t%=S0AkeHB9i^553{TQ%m9TIku*H zzry%6-d$aV9m{S?M{pyP+KI`8vumlz&p(VUF^qCGTo$f?JqozNuAf;BWIhzx9(m5X z>cx#Kb&J*5(=;^nY^6)s%O7Ztar;R@NR1s2;;pmn?JIvf+e050{OK9mK=Ul|q`}BO z8!P;G6VyLWfuAl=&#VJLktq?0@fpG$Xc}bC?0n6=Z!BJ3My-)s!@5z2JL&#@whr^3 zEs)4dt_jkX(Zh4(#tn^zIYDEe9Uk9waZYO=J}}CZeVyg^j?(! z&)Q`m7XBhW=TV(nc=g_Xi5eLEV~OwkrBr#~aeC^i$81s+G~g0(g4|CnB2P9cnBsq~ zQ}t;Dnq0r%8cYOj1QL8@edm@r;ygm#_xj#z?&wkHX!*siKlgmMYKmXkrXo>keiWJQ z2^>@-J%j^&XGDU=`1$SdUowP@>=l*~DP^uGK%p?3wgyl3#>WruM1zXZ<1(PTb{vWpe+(#uEL zl=kS2q?Zo2RPNtU)*id3!*hr4_B$lcmgqHgqwASWxR{$?R^ZRCMumpc!iMOA3{s4j zs4=7=nKm}8GF6;RmuZJv$?BP>U?Dm&X1+9M9yV?9D9&`Mm5U6_0<&tB8hFR&t{drY zWwQEH22VpyU%blS+up-%&fmKqZ}emSgxT}Yz@0zcBJb4J*^ayU10wW|TKQ%e z>e}<7pEI9K2|d=?`@%bH0=;fnNu(e{mw(d)%p9U^W)MFw^=+kN4W_tp{=UPHvyy_AUU*KiMf{ zYo~icJ7)>zx+QeOBm0zSr!Y$6bs#c~i~Wc` z>?XJ5U9a)qdpSlz^q%pCXqTYs&_kbYUJHqj=~QFrxduWMlS! z|Eq^EY`3iaMAIL)mZ4;#XF)YdK>@euiGxk1VXTO~R|@WHZUw`(7pTw_M#@|au$#uc zv$)L388Qe3ZKW%DOjUo;74qJlS>*r!HYd@su{q3|(p@Ba`pI2~_h*@J>bB4+J_Kk} zo9>NSLGRJ|5~lR-p-7s^C=DhoFHRA*L>>Kh;;d$E&H8LPaJ&(MkHg3U=zfdyRf_OUW!bDp+Z&lP8P;(PAFT>BmVw$H8>I0&s$Fq05?H zFc}e>RKTU=XuginBYi2;Xf*MvVDX^sG`uw&xOK@euucbH@3eS2TL2C$j)KT~b2edY zH&-&-oG#{p?rR2+0Yxx7g%mG2867|gk76RU-a@%R+yjvD8>K+b2F*=7jX~0Nsv~mu9?N7O9^Y`mzXFzCa zW2uUp&yC^1^?~f*T2UrfDdR;;7Ew@Av$N4$1Ybsc|RZKz>d&6z?NqdBWg;|Qy zR(gp4LiO*b85Bx1NAd#)o0pI7zSF4E_nNn%LH9c3=Ic)O$vgNS^GT74$!GM3Gb3Za z7RGJwPZui|-oO7vQt~l@Q^&Fs6l;ckYN;iiws{4jN*yHKzrn2ZU%%XO2EVav+c|zD z;yK2@oTO($;(YfL=YjK5KH{0C)XuKqEh7h+0Ze0W>Q6U%dv<0-#C$*TqIX4!p4W;b ztkzS1Pje2geE*U)JyibFKPk>8t9I-`!izZ<=KS<N0bjsuJm0ADC0?5f;svLB5 zB_oI?)kKr>If*cJDH2f_@{}~tMpdq5K^5d@D&uXAx3gJ0Rvfo`Hp|yZiLd<@{@h9O z9h6D(ZrZLfI|ImO97}8@xo5sdiZ8uM5-{BZ?AX&Ddw%lYK$+V2y-AQx$hkKgrFE)x zcg6}mY`f4XrTZ8!a~kRetw6pB z)Q7M4ZQiAh*M@6Wjd%T97RFf%GJvs>8ow^oPHKpSgAR=nwWPUWn~uYi}T9J(M#~m&go=DehqV-$u;!B*Silupu7p;ah~;{X;Oo~clg!;0)21>@L4QzuDogYD$JN%?nL(`X6V zr@DnlFt40d$Gpw17=e&|35D7mmX$ci(d=fcoN+H~@?i%(=(b7q%p^>%K+vB;o*LF* zwGFd`J`{R|lP-}42=}pkI;V$)RbD82Sp8(e((t@+j0pvE3x_ob-fdCUWO=eDyu^qEoX88-C)~5TWUsYYA|A^Ky0C1XOOC@WO8R$ETQZP2Ys$!^uSk|)(FO>H-~_| z&bIV2mD9U`-ol@sW}M|pm*ORF5a(gjShG=_=f2%KUni$ z$U-yg(Eza0am>sk65aB!o;0UL?;0=BAMO?H6oIOZp zsu-LFOHn{b#|DX4sC|43TgmCa4~nhNRQmK$oNogqKu z+at88N_#F`$5t#T+0Bc24|M!)eU8-Q2+SgrY|b`1VunS~Gd;O>-w)NEeVlEtl{>fJ zBsgs~CbN=~wX!@N#ieV+kDFtPqH@tu5NS#N04o68J2cb%EIQB9a!ZFPwL}QYYWP5R zl7tBmo9pBO)yrBR{fF|iU+a2}{d-|A;C0Z(omVm zC13nv`o-+RQzT6Jrnr>5iV^#0NoTr_wiV&9t{H4RJ{IsK(J1KKkz*4U!?x$+7g~U< zCnX|s6c5Vt=Vi%719H1Z;GSL*mquYB`_Jjy>}7jY~CLMZJYV2^hs0y^cF$DQ|7T>0>CuZ`WdF&ov!L6ngnVo)}wH7}c=w{cvDe_b*s_!0mLDvT^igW4@4eti>=Zc{8ThaP!^j zzc7=@w}hH{JYs#6GGy&csk|77z!W)+n<(76=;{sao%FYrmVPm$7-zU=ud@5%kE)c5 z5Z2(Ct%gx)J-+5-h%%HVk}G25tBqX9(jBEU^|eMi=Nbnd;iX2z!L^yflw+5aT>t)* zUp{FF7p~d;CcobAE`@I-@i@uC+I-=fwF{d?bM&mi@7ki1zZpKlXvU9p4(A*Pk_<2o z!hdANwT>YC$>B=yOfnN_Y*yE7xaQPhv4+lJQ5JM}9KPoCVa_pNbNnnjmJ3*bydb3; zG+Zc^Ut|EsC}A);#7{}1gY=22dA#3z_VFma)U=LB0IAFGx*#B@+{D&@sSqEn)av={8q%oYW=}QFYvJ#@tjAHitp84&tk*`ntnY?V zYW@6*tnbl^EMlQT)^#h@i%dqBUk-FQn$HhQ44)eb2_v#2xzFKT(w;tC(q~7qe$?L~ zcSdEAEA6sglwj($R;bs^mi0bU=aTWu(@c>YYwXe*8>`-Q$u)HGcU1CUBZgjs|HWL8 zLvf53bLoraE|)PXwBuLZJA)MbwmkVjEpVu0Zl#N(e8V{CS9=3J1+c@5N{^1nJiPTX@&TIkk!vL^Q#-RYtSyHR> z`h2E<<7|3n`SDzgtowo|0277H%M|GU+l7<*i{k6p94Lv^I3eWXG-@u1C9(k&BeZI5 z>7`k!v`0l`iu5~7Bv)Ze2f?kPl`%yYX_*Qstar&*!t{;ASlVt9N#f;~o$C|0OUgtb zdD?4^H5lNIr2l?^~D%8g84UVbR=pnMCg* zOkufgmqiqAWl7x_n3K5K+_hNQSsda@642F0vRt0C`m(wo!UtpcdV{cOtKG$VoiF2< z>fW2(u}r5OC^5XH3N#do+dFvA@Pb92Ma_9>IvNB06A;kdGB1#9bX0<3c-nO>Wok{8 zSq>!B)AhyV%#Nsc19!)m#kwh90kH;0t2&aF1!;Xt-bZc`u;e#`20f)=_=_MAyX*V9 z_i#@O3`Tw{_TQE;#WNOGY3s+nux37y2n3vG<;4`CPgSm|gvJE973KuHvWBXYF21R; zSMt#7+)2@!!oYqmZ7qp=(-3V7lwWK8219-dFB7=5jgLw)@P*nTl&eW(;c~zt7+S?7N}H% z7~LM!@as)gDN(vNBQdPCgZZ{VPKfNwCl3|etXUffv^n+TPoU0Quel>(){Qog&kxq} z?KD-Bp`A}?zA$xQa)3)GfiQylpx18-JOdL~g zIGx0a&GYr}@cF&c!N1w~JAEYr1B7}~<;9qd<0Eix|JJl=1GU?qE(vt0U!H67Tg)9k zY)^K{Pj*4RNtN??!}Z(?nQAv0BlXPD-O*>$Xp_9@QdNG{t7|o&ablQ5_g3I=uZx47 zGk&?(tGm!87v$n+>9PCKgu5z=$B>KL`uM8rQjQ6?W@5qQ47s9azJ2mfjodM->mGS9 zHb)&YLqK7j)(Qs;C;2jGoe}yi-NS8CbuYL@u%yAp4 z+5m~NfND83?9M-Q(LElaW8%y^=29@O#MYPmRzM=RCj;Tz0dJGBg(Cn=@@WLf1*t_n ze30AE;XkW&-TTX2oKkaKDg35W(#Z=2mq~ObnyBSftYQg-AdigqSoo;!?Mz zeHiqn=$C>6#J1`uzUI8`kXXSwqRUZL#qB1EHr4ZsHFw&d@1CrXNMH8jDN&KBL3COJ8(3on+w7Ba$Xo3Ntz8n1nixw9L#a?e2b;zu&$ zO|%1D*R>DFyNe2ib_*X>oPCjFA;;rNOS%(QZyP@*_fA*?dJzPW&W^C4+~1C*~N72CJeIt~XX zZz_vG@D(IiORwxc?MnYD+0+>tZ)a!x%4+BCh0;xzSF6(=1}XM&p_*;~;|bkY={T#)VfSvT4;~*DfbxT~r#*#s zU4(V=^XqkGHHb{~`_sSGW`f#-z6G%Ivod)JKd81VEI7~%=z9hIopaQCtWKXF!4yzh zKaync*{?1#n!-iVuU(}daW+98%7llN1hqH_`R$byPu0nbj_-^T;I-MKGyf2))qQNz zS>kl^mbGU?H8s>Vwf*ysD^PM1iPdc@!%68eBnO`w2?+`9?TWF`91ewJ_ zT*u#uxhT~7M18F`0C3^5D~Qoy)F*Cp=MScLae$r1$ZJ-NTYL3CcU1)(V6ZyxUG6;N z=R#kEWc|a4f?oxfX1A3~^>ZaptkIIZ|VaxWV4QA8<^99*d+e-p;Am9S7 zmUsUND58g0h?DT@pd5YuvnZYIsEcrTeR#Z#--SLC!oIjIYp$uRr0VQWk_ouS@F7nu4kF(_aNE{#`*lE?&1Ab$5>-r`SKvM!F9Aynfg{OM8C z0y8v?66Dfx&gVwHPCWi__IkUVu9tGEkzVA(nQL;88Bnz@j2${QoH5=zh*qG=>287Q z;ME~Ebw3Gk4KCep_}t#&0CF}qVA%H?OvVJKCbnem7f9TcS+?;os=PGv1O zt7VLvTR|nRpzz7jVOrOOf58*Fesf7ha4oBn>}k-OLj&zV%cdUsKR)VdR`tpq&!vDk zO5m+PTQhO39oacYvB@z&N4|#EG`C4OuY$&y?Ho8D)l3++K*rZhayob0sbPTVftUs* zuyk1u&6&L2f7nj4+i&X>jE=gfSzcZ41d6BZWz@hO?M6^0Ya}O-Tfj49uF7iGfx3vV zy=(2n6`Iu!Lb?AJ|J$l2X`7*j13&Y7Z||PcdcUt(6 z7#RI5__mJc_wAe&x4dvOvtp7yVzLBUaN--J%sE@VCpUcXj_k*ed9y-kzH6EJS^l)O zCEif}Zu}O+Zu=XLzyHN`{zkk(@ZF0#q?3pXxx~)V}KHf1!Nb1SIu4{_XtzATqj$u?H0`9|33&0aE#M_JN%?=CJUTi89M zj`ihY#tx!!V_+cd`La*V(Oe;Jw9tPbrDAXCp+$9;N(~Dh>uc`EDOL20nN+XJYFE)NpVocl!6FhDJcX~c^;hjh(MHXoUv)%fw^9((e z-j|&$npF=##(Oba1(wu8r`Po#t}EX}v?Z({m!Pc(M z^=J2~daa|{(qPPhL$+B`G|I}<+%0ur#Vemz^29H_GD%-^+%lK3Xf)uFJLuq6IMR1< zU}-Hs$*A48^XF4d4c}Heq ze~LttJv6X;Ex#xDu>a^*5Z~x&v3S}V{(C;okg5g?O34gU+0K%1zH;jgeXabV!4n}| z?bHzJQty0EL*La1U7rg|epzN@3n`Ua79zoY=HGl3M=!cF1*$|077+j15GAZU*&3pN z)W0hU3X&1C!a}D3kqR`k=8I&g$o-=GWXP0b{P*6;b#MS@`j;N=0`JRWCbNGQ^t5nF zp-MTmw5t00WrN}4ah(;-w;g5xOs2TLG)|xfD!xIf8P1hUQVZDN2=o8`qmbe#acmu+ za=y5ZO0hoA%JZ+u446&X(d(pnOknR~`s%M%5HfFNetdn>7EQjR?fy9jK@u_qC9$wm z^v8O-zSChwL?UpmA+i*!=-2h@I^-ZGiEu)%N!&o^V816bS#IB_IO&k}SqR%Sz|WtU zHL$B>HX$LOIJ;MF28U)^Nb4=$xx>srS|%Sh#_>1z_MN?Ob3i;J=G6wwrPQ1=Z*|!$P7M^p~dVbs~@5D$Cl6bjmnZ8A~ zNZ?ZU3O-4ilB2bL>MP0>F|?j1mqP?XvL~%9v-EBdm&yvKb+t7fm`LO%YJM1rDh>Q% zy?OxyRvF;*<2M=2Gh?^KfYDk&3f{h|sDu`(9~J197qID@r<=DTx}ryGyubUcp88feZSJe6uTRY@JOM1!)zr9brY8dA zmI`5cTl_a+Pjnf*9Gn#x7CJ62FY7V5#`qf2Wp%K-?Bz9;yJZ}aOZlWX7)vtPk>Sqw zR6^*wD4ngCFvZCI_a zva{}6!pwFm?d2{Ma2G;d{PT2%az|H5fkEZ-iS`X$RukYIC{{7kjbLB7O*S21%kpnA zRCVpdp2X2N!s5fDRCvHZ_EOZSswzfR0}LF+fq|$A-VCp8Fp5$vR~<8@9F~u%ExA=Q zz+!#K71QSDmX{hS1W&!?Ge}}Y2yeS#Bqb&oNB?jvxO(>;&Zqrc4L@uoDguSY?LBG# zFro9ewQ7DoI`~!)n}55hs|HvGt(;WNud;jo@L)9D?_e>=0QKu=T;I1x$s_rj9+I2g z)HRT@ySFqSKWU{p!YLamnf|%3DNNMbK6GMNlZZ|V(+~_y0|U=-{|$|XXBIqv+&5KQ z*?J=sK_t~wZcTVS3f_?(>%)8X1bV0LL|%u=eNycib@`sj4>^X)743Eh3Z<6+@jN)U ziaD|HhDchTG&3k$R4(;xCv7c349xOr3l6K&!zcv>5ly&9A?#jSnq+pe8WM{9(sDz| z%>`SMH(FQ~pgbYLPDt<|Me9EJIv{En`yJrfx;KANkYQWxsK&r?Zfp z#kF6FBw|7q(bazDP+BhNDWc5u;Sg0rQTaz82r1k1#r>{S4#Vb@4C`85)4+?|^1ut2 z)Oc~R%F7iA%o<%MPieHF?Rx4via^x+iHsMKI=Wt0HSQHR7_QQpq2&>J-|$wpL+`=w!eDQKv`odBty=i@)?el&PWt5(SA-t=^C;>Z-0%^A;BqoInFglInfQ zMev<2k1M8>?{D3}Y=Fua54#PY|K2nqM_m9QTdlt&)0RSE3E1~+7ykg?ibnttj$cTA zJV;;yak9=h;<#X7D#g|(TxY*4%Kgi-@pY=rK`LQz*bA4i`;LxcQ z^$pf%M}G8p=xQ530--s-@vf{@o$!7y^954hE=Wb~%1Mpv|JMTS-jb}=jY9ZNzjuy> zE09qu(^nnZtsQ<8O9YLWzE<)63r6b+;a;x|$D!k#fx)bdWR>mLr(vITpGhvFGc4ZB zfC(^{^foNBsYTVX><3_~NmRcA&Bqwh#aKW3P6o4Dw#Q(Rz9Xkhbu>265iMX^fAQ6% zf9(Dw$HRT^*9mJwr(-tAD;Z>8=R}%S_1^fp`vjIt4CWGf?X>;ug?vdU%UxG{_KD}` zotOHx#bM~mCflHqn;oq~$&ux{g*VnKTQayWRQ+Na;CLqe29ON+`ip|iB+YAczxt zD_JAJYis@uro`bosCKM6He1G)(;h|$I3T?1GWWXLhJJX%Ek|I!zr7gMHpvXJ82mM> zw6`cwXx$OV5bu7+XHlo$w+JbP$Ny+IMvfTjz#@<9ZCSGKg6!Zu%Fy~)q3*h#@UBWv zPnVpCoC9Me$|PmI(y2gESkZMt>Q3ycZh^PI?U8zZKA=Tu2r3sn?m`cqR#=?C+6dav^lQ4`G(2*DlM8hCFN@-(p{`P0OKF%pUK zSRE&G^73msUryMVMg&r2hqmM@rOei1TD$a5*b#0OpZ+gCusSl*ulUMkwIAe!3`EA8 zPQP+VCnvXB&4+ze#;%83Rm+^8J-qPHLf+hr>p_c=@v^`9&VXt(Vo>a8DRE?{SkLwO z;~b~)p}Et|BfM8C&N3ux5kx0+=j@94_FN zu;%Y&lU88p1Y@t^rTRagvI>4;{#~~Xtg62eLbHJZ2M-@iuZH=8^zVYT;KMS2L?&1aicrkJ}hCu+|l6wa+=sOgjFqp3iSSCTZof8FUNiM+8eA1l-y{Ljw}u?mju=7g}IK zmdmGuY*j8{dnowbDAoOqibtOTX!WdElAWA>1(T5v7dgwdc{}_n;wN);=bx5G3vHMYu8pS+2V)>8W6pNZ2NfLiY#{Af%ZHYpB?oQ%vq z<#grzyaHq74^oj5#$#qSSn}h{MGuu;4*{G64s-gBBx7lgeSRm*uc*+_5B&xZ03jGhn3uJV5v8=l{%%lw%FG2dK#n=qhw@Tz_)W#AwC;HQ+ zIEjl}f|a}Nhn%aG{VnE%D4_0N;OQRWVCGbz?gILQkX`7Ce)Vp-dFo;}!Wl5+SWO`r|+?tK7Mfvlt(v;ENEsfD0j)p3Ftta9McuwjQVt^3&RQl>% z8UL5NU8pKzWo<2T&d8o1+|Y?vbe;mzper zuFUieS}>k#F}Psml|GXJyw&s0g!Ye1CI{um0z<4;NftD+*j#peYS+h`!B;`MOKKLU zHs#$-^AFwkW3D237p1EcK&@X?HKdH2%L2m1)mVjp)Zq8c70GxX?&43d;WX*faG2uu zYZ1oc5dH~O&1UZ3*+@*=%mqd6G^>yzisv^L23?ocgSAT&1L&QvQAsZ+hgZ`{Mu9l_OCq+m4(py4*CZ!_fz zB_K0Kb0TkCNTD>)<-0JkB@y`qkSCQB;}-EveIzd-rN;`_py|7`l)W6vj^riP0G2NT z$OD#5`|ExZ1TPS!`OVY=V%Mk?bSi+9h}W+5r( z#O>P-OAO$J7R~YBl}_$)G<~0`XFXz;JG|Bp>Sexy`7ANoZ)^)edy;BVW&ZD!< zJ57DvJc`Vc_`uOtALi@Rp_ROyHR&v*a$bLfF?j&8YVe4rp?lAnz;kvx46djg$)B`z z2Zn5U4=EnzknZ^vlczykudwE3rk- zw!25Aaf)~iCglSP@wO9aMHrs`!5J8^Z{=O^#YpzxUMhg>QBkrxzR+N;nrloE3s>GM zRqhHcmO9pXBee5{A!LnQj?RLFbk-m*;hjPcr`@fWE{11o78f4L31Da27l#&=Fsx(3Kscl z5RvsPP|eg&9G~TM+l<2GQMr-UZuT3intJ|b$}2i{QEq@~=I?eD2^2e5KY2vr-nJ|{ zIkDVlWAMS|%a+u(*k}1BxoZs6_)nj{XHLKPhV$O6rH-)&MroK_`Zj<%ie=(66cyKV z3nR5Gs(dq?Dr?zGL0w-Ymfq@S)W?~+-mN-+>N0Cd?0nci%GEf>ttHW$LMC#m(y`%x z3|`Bgxb`1X7>d*2ICv)Ju)rEzCf`VB`BwqO1KJ2sn;!rDW&@QTlEh?O&O23jnqWmFg zu)aP;T3Xr_zM2x)pZ)x4jqL0piFhIZrKYIvBTq(u_;XD&5C7;`DH8MLXG%y{=jGPZk$*nV6>RVJ|8 zdP+_QpUS}B9c<}YICiV7sOi2TYEERYw46e}5-DddpbDI3P!{0Oh5nB z7F;pC#A<7ZeG=O0#Ftm_=B5R}Nhw~OR=U%3nP5hXT+t7cGU#W15bE@-$mATUbHV0A z>8T#0ys|V%zAkjT-5yej{_XAY?tWVFGnd~q6CAQqfCn9oXz473X5(6uZx`jJj z2>_0DomgG_7LW&q6^C z1qn91rv@?=*eMPO>uYH1<7)KuE0s!^?{<0mSu`Gx9wMqa-|(Bsn&39|E#A?hTFsI8 z@{7s6iJj$%z;z7#99Txi11c9m+-M&6#>Bpjt@wcjEGR!)c>+eI+Y3x_ytg(S&bNaD z7tU>(Ib_cYeKwQISF=r^eBqeT|C7+)$h*qwJsd6&ldbKDj69(?^`C-A+f1H5&$pmy zA^aaw91z>O48XVfG|QE6_)QQ=_;CN#BL=mijGhUpTSm1xG^reDm-Qe36(Qp+wy`u! zs`(rHh2oXCR1=74Fj=-ITwKLlXjCmT?H<%`YGCt-qSr7EZ@U27j@6On!?$~+Ae_GAtwae(SxlE7q0!uDuD1nVwEHJgu7b%<^nVkq zAzyZj-pPG)sl-7^GQqza(0YTYRVl$Qqx#1{+FSL=o~m2fpKd!W3!7{`BP1p}W2^)} zc(5|vu^J;rj38WjkRL6}q=#pkBx1k*0^x9Rd(Y^%^)kBN8Iy7D>0{Mr450UBm4AhI z_J0DH#cpb<_vRii^gs@TrleFJRxU4v(#adhH`KI)IjEHufG{m5!Gt%&0ki#99p)g1|m-yf-I%H z+dLgM%h^p*o)i0;rX!o03*Nuziwj8apDM26f4lp-KJiI42i#ch|5;!8)UyO$^{awJ zBqI<5qY*7j-F2SIqNJfW$iXcow!?Hj$7U7@q-YX%3QhHl?~p~VEa;!36A;z+b)QAcQ=|^rj%Q?gji^FT{<>QnI{^BstSHi@jtUMn12Llg#Mt={&DCN|! z-_q_6JN%Aqc%uJkXb*e?PvM zS&$I~18Z%!q!&wWxjaY7ddauF5NW>C*}0xw(G;tx;~PYJL#t67f#hUmAqUVq{%#%% z-kOZc@)5Igi}JvrPE$y3({WHN|5?hfCS7%SD-|M~5&EtkeLqI)qmNC9sb!F&yraYm zk%$LU4&Ac~qf;94z659;F)#SO{E(rRryyL7`Q{FuU&t&B3=~t703NAT#9W6bCB)5u zf*H!;#h=@+hlxu7WhU;7&Go)Nl^P3#eEN6{zwdjx)!vNpa_UE)D_>_-Edw#qn?%E~ z1MdChuDOh*vR{c7lfnQcH|(&-W@P1B<+7XSknKP+_gZHcp;qUC50)9GsfGte zoSR;{lUQwgEwe2Zzq1y)a49C))&p9CTo(O-$^3zowDCCB`ox;!BnV09 zf$XIsrDd$tS|4QUZ{?Rb^DHH2Dm>GH8J&!1sxt52S6!a+W#4{*J_CR-**Ug_K2HF~ z&olLRKOG*m?y#K3?Prs1UD(C#-`_dGSm!pnQzaB|!@}`eX}yzlV-N%VSe>!Ka-n;M z+21KRr^YUNkKe*F>iv8LH$p$Ys)<`^B+2Y2TuhCX**q?D7n*-Iua{u8`MN@Zw-}j= zK5c;2-90thYHX76NRTarKF+0wwv&$QxSXL)*0!Ftu;J!)4vYS+x7$&XKprTBi0N!R z+i8uW;tfH;(+Vg#$nJ{8B&r$kci@F;LX(|52L9m};FU5{{a1?td}X|f7P?cj{*zZl z+uPg7YC`Qdp$3R>PD~;dg%(fd_=^BMV$yAyk&|;9s@t2&SL7j|<0~f~{ngHoK`cq| zt8X!$Z@evq*l#e7$KkewKAY+kKFqAy3gtX2`_b?$yV0V9PJ$KnG(n4Y#aN$B#^}F! zqUVg!QLv(^5WGQhG$DxFM`k((w%woqUjwSo;$)VB`s{zM1YE?n_28!e_|m9924f_lig zjxAz{^{UJ{cTAa??lpekimC$F#pItq039#|rMG5of+%x)LuWbXm#Zv+Gk-t=r{64c z{Ie=cyhjkXjpd(DffxyUXMhHB^EppTWo_~F@AP3K5#&+M=CjH^O?BGc?7;1Tl%}xK zG0SfQ74y2)1rMAn$8oc*H-j9U${1KIcZ$s$o2kW3PPx+-0}>^SbgJ_%$-{;_qrF0C+tt4_QTm!;tbTopqB%LK)*T?>oO|<=*CSm65)nZtK zdHiLU($qjC_pj%#byrWuEB!{D$@Z;%gzO4l?=C{^=DJ_Bd3OSYiW?SE$7L4nVtdjVk zHS%zbJb`sNv|~5G!3j_IkMX1ijd8jX2+HWG7*}( zgkWD?YEH%Cq}!qE6*Zi5sV*kpeA%Z|X=mt;MN6PZxlU|~AZDi9vQJ070{p42FrQ;hD#}KwNIPy!GfoB$>>yoM!ZN!aua}>+ojFNqRcsH9-Bg?jK#Jb^ zV4|s2oVh#hn5o$}`Zm$lW8xM2LUZGHL<-o|VGhAR=aI$iDH0%9J>k?*lPifpujlKd|E#EB)_Ameh=j=H`9J+Q z{Q5X-Dqj2ZEQGd8t$lZx`e``r9wd=qSE$tYqw&R`vH`suAdX)Sb_0Fus2lV`K@Y3e z`e8=IRx)WNzWigTk&^J-M#4C^f2&>XL)_ww86QqKZK1Ctzs(tnOo6uywTk4bS$Q!9 zH{>gSG}K-?&q&aYY2RtQcwqUbn&c%#!3vi}M=-(9`qDc()UOdxQh5DOBn^jK{L5Oz z*B6@}8MOZ{6>*6Ubf0?%K*C{ffBD-tnFlHLGfqa_=kusyaSY)(`Z>UFR6-cAE*x5$B?2d0 zXovzrn1H3-dcKF$cILY2ieoJN10f;<6w|HY#SEOrw_*7N;!IdV8b}C?`i>m+(=J5q(4Gq_+yf}K>qnoIPw9eM)sQ%%; zcq1WTT)O9d9$N_4@91$ecyO|K`Y%3&7B!4?Mk|0nUk6zg8bAH?X=i3o<6r3kwC;kd@DZzScB`88wK-=FqRY3djnLPA?g-2UWGADtGflOa0AH|nN;-QqqIs#C^{7*v^l+$?IkIcJl1jG24V$W3GtR@=60*{(XQ)?xKtjZ6 z*jGZ*YOUs~$DfH5F_CC?wt`3!Ts$>idF~6UE1???P`7h)R%Oo%t9pbfbzn>M-V>#Qs(O(*?LPYO=vM<}tlljVE%qO~Z4t_D( zp_F3FGZguAsb8&lm-1i_-J_W8*;02i$ioq%?=|OA%x19{6L9{Se1zjN%+5?9*Qu|5 zRD8l_%3@(<_@o~9k1lwbf2We$<#`Z0E!H<h zSNZSVJLyol+KEr+3UhZKG$_&85KIFd3-QvI46xD2lVZZA^hi%zQ5~_jE z#&=#{T#k+6*UtD)+D-a?pUa=TY`LySm@@W&p@&(IcTKK)vz{I;{4j`FcUQ@&SuNPk zFycSN#Hcs}@A5O+@Jux`2AbAOwS#??3P43OP% z#_qM;L8sa2%4LtQDbo#_49ncb(jkD@1DeJs8H%f2E=JhW?c3rTb(R16HajI;wO-av zKbOuS{YkYtrJ;~EE-i)1s_&UCeY%sYso{kz9i=hQuS5;k(q)yOufb)fuOfw+ z)KhzaJ6zFIVM^bJZ&C$`lXdpsz{PY3?bexUpKlH8FJAKdyuv?-YH%0Tb$VlPYW=n97Q zxADrFX5+Q|pK}-vyp%~Ot2CpTo8_XuGO|WppKtqgcFBCxH`#Lw2*7l91$t+U?q3{P zza=ZjcxHWe=Wt-v-)92b+8h=JrA!`E9r!$W zS29DKJY%sxB?vPV0W@lYuEN^pio<0b4fCM)mBi#!!94dC$li1>wdb9}!u^A5kkjfx zk?v?kp#EnAjb7%DH0pH&NRtvFwW-~1t8K+Atj-_LzCid_=>zBOh3h8N2eJ?b2EB3m zdAA}r4f#!m!iWF?3DC&n323j-8%8RV_6AkmDb7aC!AsN3y6kBDwxV#PdSLgv6I6RW z@YLV_)ecR<+G?GG^47vO$Fs!86w^@Cpitoc0D}v@Qqx zo}q{UUxNprBb*ha1*q79&c3VAY$Y&RW77)XLctxz#K1`wvQ-Kf*^i0UyeXFD*v{ms zce2t4^}fgClx=*{Zdt!IsU7alheM~sL77uvy`jT>&Vm-L6s^6#b95Lyh&mVu&IJZ@ zQCi^bL($_hy>H}bS8ki{e<%vGIj|0VMOMQ>Q(~6Vmin5P_VxmUgZNN<<@-fNB|@YS z3|>hm8g&W#y%wrwV_zbVc@&hI4Ks8Nwa7qr#DlyJB6&udN%61cWx_h z->b>Z%0|mwfXNl!PWlJPJ0#SD9R2DN{96qv+9ch(UXQ=}X*$E+JaDTv3)GDokX`EU zcd3$8vhwwG`0~@v8!@g4yH7<~@g3cABgM3dVz;jz!&mMG`in!IVRy984nK)`YStNa z-KP)fKlA=nVLCP9XeM2}26iMdI{b!;xwWhC!KEoaKl0YdnaaO~w&nzb00*1Cy@ILb zN2D{*BG5}y*>UDTlgHM?Z(g=9kT9>HmjG;u+lZ1EBl#oS4D}mx2B61<(AZPPv#}9Z ze!0FWcPpEwk}P|A5;u-ySs9 zOTx80%8nK%5AAn9@{LfUbY1+!p6dGp-VJ0T$ND!P%I;B~yM5ZQoE+16wCd(RP+uQ| z+pO~(58PT_9dcm@QTZpM~erT{Pq3j@h*2*^=g0DP+<+^YdmVV0bc6a z9ELLIb)>8>91#}+X|*fv|8n>`Pj?ON{lcAFjm>Xh^vUkmm$SH0AGs!Uq0rksKOxOiylYeoGg zt2eo|(%ev&S20rB*T@~q?$ynp|L$NYeN)#%I4)F3^j{I%3$;F;S<&dXQg~f$yaAId zOi+vz6%AuNzC2y$D4*SBh)mKbYYV$0ibmL~{J!#%jP|1grV#IvhjG65gXRiBANi5` zjFlO>O4%`(XQYC(FZ!Mm73(ONl8h##ZGL+n%;IUW8oyJj!WTSm(XK!}(XiKq7^WoPKX*WAiOR zDtNjzx(sZ?*H&E($B-9F035Zmu;0?Gr5eqBnU_A=t6N|CzGxT^|7Ud3 z5d<%rX&|dUel9o8oqBpP;b8S=88f0i_BtMcdK87(aOg`5Zc!|nO*<7@g1|@VGm8Q? z(81Pj`K$t=&!kI^e!Z$lIUZ9&-5Gk5k*+-a#?&$=F4oy#^bGZq-qx8Hj@+HQ%`yJVfWf`bS~+f^9rWH>K=hxX97Q@hDE6-)Db{tACnIHSj9JA#g=Fyy`T}+dE5q_1_zxzz8wu8D_Q$3}T-r;L4pUU4 zK)Um9d;`4tTab8`l+qF-w#=yto}+rM*@uz1tz z``fps>8+2RDAbW9#Sy#|?E(o^{S_m!c+gzhFNs#|S2?Y}!w=&MMd&#{c`N~7LOZ(>|(H<(yH{c9baeys@~|cdjC-%Y`AyESC+ouNU_ETSD7ijDsR%OfFIv(|B=v3b<5M zG7O_|=Z)zgmxc8{^~IYHOuylYe5NIclKQ)U)=O7-SRhuVb85n#b|tY3N^Ibz+?w|T zy!Vlj{B!)KtelMd#NCgSPaaUUG4PsARWmEfl%Ry5q`OO_g0|btDSAQ*1C>tB$~Dvc z*oKiL-yx)}Ep5MTs6QA>Z|C19@w@2@WjJhhxmcM&;P)?L0<=<2d}O{>K}DjvWFi7k zVolY%>9uMWb;v*Fkt)eF`saNk{!p28u1C*e<{kxTO}JaDC3`qG*LM!owdBy3 zIT$tAFj`yt=Ef13KloF%`05@oAqAQnXkEi?@yLN3u_%-`Q-WyNNFM z|L)-J`6bNagL#|8BBLTb5jAWkB4WZv@Iw~@Kkb|N`{D9-z>Sd%{=H#VtTi+|r{|iw z^>{NYoJ92a)u##bGDaY1#ZFEhXn5%1Tm|a>} zrW@J?BL>87*B|PpCEkQPe5?9woQC^%n7pBlw)& zI5L@mKMnefsESI7w33482HhULKxtJze+kZ33x@?jI>jLp+mJ(RDrh@wo zc-EtB`oK7yAcMJb8U%B}VavOKYaJ?BSQ0+tFZf?bhJLG8|LFSP{3;G~`OuZ}?g52hd9Afonnlfde*m?)Jx zctEX-)`kMvz!N)g?t{;a0uWNwXrfa|e-ia5=HfQZvLBSOjrn-|UIucoZRXu~it>un-PRN+RN26o*AR5cT z!$=ir{`tu27&Sl+64K?{SbAntpE|eL(x64yjP<})8^UMvCOtN$Y@eov+0HeZL#F^s z?<~mXu$kC6*%6SeP2Oh8X|U>O@WPT?^7vP0$Xz7Rj*xDfj&@X+k>>D>dA~C_z0dl7 zt9jI&w0s^`8^`z`0|B*rew~P-zHGRd4t{At3rjONj0sbHdKL1pnfSqGR4#20c`&sw&ktVz~N+#Ma$ktw%Mc|oA>bSXSMjgOs zL2f%+Xing{v1%7wP3+rF?!s8{-SB8 znCLxI@a57^fQlFbaf^r*M%o+mKU-%YJOYC)rJ6Vuw>Za#hvF6;^>jSxX@Xtl4Zr%M zOxjCJD$AXIfwFh|?Fpz=ilsZe^pUIY5{v0FuB-h3=$Ek+l?_;G--{kp%8Xz7l|O1* zF8-#U9qFeWUF!PdyWFYl=QOuZ%+3odAV^(vj`8rnDocA$V?N&6eQ`rB$o?$BJ{Lj% zjb}QddgV5Z{Y-Ba8I5B%0F0xT$2W&0I7}gqo4?PF6b78 zv-dL?8k@B3kf!?#@2CXsMg1+|R}g9HHJ{#wPArEeB)Sv)mu}GXN*|f^nGCRhX%{|v z^lfq5hqN{}zCU1p#JZLQmdVwVRjDXrv-Yz0lE<;ySD==ABYmYBnvaW62cgB z$LGC?S4ZC7w8eOz!FL_?|DcE-Ou4_pFBLX#u4GD0yyAMUBmTg^_}Ut%2Vcux{rF&X z`5kETetys@n9^`gZ`^xeZ7uib$QOoaZN>YM;)3$+T)BT~MWeK%yUNPBgP)GiS5GSa z9BONuuqx|=7iVUSDE=wynqsvYp12}&9t=!c+%XSaYB2EpKF4hw=NsjJ{Kzf6?4O!3 zA|AJ-yzO&Swokt8w=+P|2Vv1cp7r23tY~e&RE}`1ZdOsW`;=qvUCiZe;1aXwV-w#M zo6dn2T2lJw7Bycz4J*RM9+ToY{e4c)$EEcP)t1Y=dQnVSrgbiiY*U?Z&Fi#AN`-s` zRDx9RUKE-JImMJbr;;%TgG3lBCLU=6MYaFwzR~1Rs^paDx9vXMy;jJdy+QBjbcQqp z#aC)Hw@i+FVn3dJ;>Yvm4Ve33?(|7@wI;1XVyx1|-Kj5}x3|RYyzYOn02r4weN>b4WzNy> zbtQAaTf8@iY2wME8qFdyfy2kg{<%4@iM-Ql4D5cF61=E1Csfo^cvas{?LILgw<6)h zXrskzaZ@z?CMupR>i5j#f_3YiPu($HwZrcoWjU)`!4fVG-xA;T^odg5WeW0I?>SvO zY&6m-R73^~M3PQ@M(ACbjm-7rzL(H)Pq!1bS2(gS$Eh7#M2=jeG|N5Pz&B3PLc*eg zIMdF7=m$iyyP-ZzCxqZ9s2!ypb=e(g4BwkiN2{+-BaZ4Rho>qW1Yw1!+bXqOWm7@# z98;o0Em&yT=7Gia6t(Yv&R>od zklmY7w;O079J0YlY!XD)axP?QKx(JnF}kT;_(DL4JEygnDpSoXic`tLVRh%H*|!(z zpPo)!g^Z@hL~3pFbEVBd)DA}5!Twx!aaL$FFl4Rq-?D#ak8dogZ#UI{%1)N4gI+<( zuu_!3wJ1CLXlUVU8Et4r61y)~{HNxKs*D7c8^>4vmU^Uu^TU3&DNd|9)}o@?X`gAI4ki#q%NW#2s^wrE@xkhz-@FFhIR7f ztDip>jg2iltGOfS6_@@@?}CgRlpQ0dws@D1*nG>3m1UVMa zIN62#Ml-k+JIlHm^i^+MMum^4c3c_=^at{-`%`f5B<7FZKi>b z)emkl-hRv`qq2xmB>N_h!xS@2@_kcL=G}#{qF_pL58nE-?!6~2Kta?y4v&og<*I{B3z|I z1sYt+`W4AYm{0Wc7#;Ic#@#JgH&j-=G}Q6k=s%@IbvX~|q?{_gNHXPp%@(szf^R-2 zE)7+UFPKHC=X%I;9)GR6o4wYB{%(oPVa!T9#}Y{^ebAN1KpKURzit^A_~_NGz@mBC;`rMx-N5#!P{%QOPQ2ZaOtR#s6`j zLRR^|u(j5+aq?0Ch-5QFa zZ;uiV!;`FD{A{cIS=gO9f0P(-EckZnp+plVdp^(y(Ly6_`=XCp18A#tr){jFhhYB7 z-q$%DOVLB-^<`5ffgvRp)AAlP=!py5*+f`ooU&~^Pj9@O>&UqnOhL`Ty=Nj$iRL5myy_|F_+;@;lYveQgi9hUY7WbGxgw1_^8&+B+nE+vQhyA|p&)XY0rYSqtX$XkvvehIQC5w+jP<+dOMeAXOh9Q)Y^Akj7K$~%N7pcj~T`BihiU_Ua=p4!Q3KW zLfMt?Eeo~o?2YT23I(DS@CwO2gY{2_)g2nU6kEUNoj(#BX2n&qAB2Pq*hR!!R+9eW zG~usBquyn1FNL4(9f*sIQpfmDmy$@mRoLBMJWvJ-)SHI0BmMdrT3W~3*#fyhoy!HJ z5{XKzlAKkAM08N2E$`7UZg0XbrBZQYpORo>B$-bI5#p@Bw>}a97JFknfAN^iPIUXp z1+BC@d)sm1@!l+polynh0X2#@S}Xo;Siq?Hxbp6gV|yiG0V_xL3XdnN9%dN5eqv`L z6>8ZIZoa48q0g=5W!n@Gq2_%tZD}&=0=RmxaOD?t`?{a&x5OmV&5XdEqBizsn_S!Y zz*1bs4F}vjflHLt)7}sE8{^eC-9lo$+Mv~P2LR4B-$xp1E%q+zm%iwWy~(FEEqjWJ zT{Z>Pp6d7OIea;~%5e}}W|LxgtOH|Zfp{C(jU{`m9n+yCtNi3B!mXSg?Q1F`hf^Q>tSrG{BN z>|fI>t28Wd&}lBa)zYSof3vH-JMVpze7fPYl%svtQN%B3oDMxo^QUD^YxK8%FVZ3A z`B5YUQX8_3BwiuKt(q=Q&-UE~`8u1f>DMj|i>xIZT1^?dF*w;eW!32rj9;ExIc>N` z%^5|=+maav;sb41sm(gG>k0wH0;egfC#J$fFc*}L_*iP#&APCq&OpEfD$yL$X z2*LF7F2;Y!-k&ooXBBd6P%LD&>!~ZeKt5n;h~*Hgp{N@l9c?i2PxmlhH(Wt1En~X(^1g zNHXIDC}|FQDDK1rzKtQKPg_dV8NH;eeM-<+v94B;7$jS&xojW)YkX?sEd#cfkT={i z0L;iOt@CP+R-Je8dN37V4TYSh+dbT(eoyn(T*r!;5Y&lW7?GJ>hO4USn4gxk-KX@K zx1tvQgrrEejqb5-L40eTyB3{}P+BGH^8iNnsxH-nr`6~N<`7ZUv|syIHcFUC5Hc}) z6eWu_Omv;zvQ?Nu+9KTYIURcMRDnq2ZjKL(C|@@R1c^0N;5k#>LYG%o`@066 zeRrc%nWL=Ggjc5p6p4s7IYdo;lc>O~r(F<(i3l7gbkeCi!GARd&a?3Osz69#dFk-@ z@2-Gft&6CbT+|)LA@pi+i)>E8`U3`&6r^!Q$3gP@ny&UCLkz^o00uP}(BCiu?*G+> zuLzr)LgG3EukD#6mc6WYkWebaFjxb~m@>y8t*JxkmCb4YK}yH8IxuK*`8)6Kzv=3; z*8>UBUGw1$$y=u?YENP|;>Qhsa82szwx|I3ga=-!5{R<>OOo6@-?ttwrHf_$yB4|I zuJka^Px*G#Tm6=!!k#GXrx~QJ%}$ew%F%1fkj^GMm;Ksgw|TL_uwk=WVQA>sFV*PO zKV>2>;aBlr$a}BarB*rB!@-Bdh>~8^{=gd+cNmy{?-icEK1+*^XZU^h=KZQc!j(BmNCm(f?W$lWP z61zq7POYiDIR@l9T`TyFWSncZ_E7TVaunj~d3W+T`7me2k=&LcD$ttM`Oi?At52ov z?JT5`>d;K7M;FJBlI2ky`##~!h`W^C2kp#JB>tjl_qmPSW4Pt|^I>49q0v==HZ28z zau@OrIZC>=kn&zmZ|feiD!z4J-!=y9fJTiG9QS=H5)_?d{8+5s+Xehya+w&)&4?Hs z+FOFu*-%3QyW`_cxIal0u}#oD&J))=euN@q2;JMlB`Oe7i)zv42~ z>RBanSA*?Iv9(_dOu+VSx##Jg1bOFvujMM^N@fKdRVgro1OG<}1-Wm*+s3SGWA#mk z24T#OIGkYr1Sn}t-K@{~+3`al;&@OgNHoNO6bEj#KX+89?nqi6v}Gcr<+Z5HVM*(X zce*kZeRcoZT#(OlQd0+BB=dIWAj$)B+7Akz{GK0LP#biZ9gKDl+`c&sr~G9%sMJV{ ze=Ad4DJO^+Go|+&CAD@;^K*F&-PID5JP_O62>NidFhXSuFS(YgCFN(uV@Tg^ z>yf31s4Rq0^)QX}t-#plKz6#MIX@Qys43__fB#7;IPAc=-i9&ALrhXo1Z{FO*u*-_*RcuIW()?)*@_QrEh@q4B13USk3e z0toO9cJF_C=-b$0Fa&J$aueoiEix3vMQQ@N6;3{*2t3Bx3$Jq}$l52Dltg`4>2|tC z-5Tovb60KA)yP0{`td03<#6jup^(}yxOiGFmd|#$PE7aBgsQa8_C(SOwTD#Bn}Ihm z5aq@+PbGZFGErW^eH1E3t|q&=dipuY;XCr~%>6p(1bkT%soIo#Rq`j7 z_28cV!@MUM#hMym;BJe}Td|hYZ>*9Cr6|~}3&q9|0@Juw(686|PxHp6(Ao9@(E0}H z8i>#Ra}tkw7aRp;X?3^X!_#(SRH1>i@k9W}OT7ZV9ORo_U6YAtU25HDgc^SYZ?C6u zQ)JgQl`9n^*nI?J&-@T&>)CoaYrm1a>Oz?HOt}iC)%j0Mh3B7ar_cg%?&Wnr7-fL4 zq;XgI>cT>^bZbDzl!pJ(n^X2v`}!X z-l@VUb^=pSAXwm`>9FAF8?G)2ljky2B~vnbNa_~4dC1yF}rB9gSzd1YpSGbX|WfJ&7PKdxEszyD!V;kKrF43 z-n`U(I~`7?>ES3k)=%L-=}xkZ!0^@#S=-_`c+&BAdrFX zdGD-zBR&o+sJ~(9<5li5{LoTU`1c6C_3ti~-@9FZZCdINS5T+YvO9AVw1oe+EhOXi z#(T_6SxPVhIknIt6Wp``kl~EKmY0}KHxda8#u=KKF z9#k~%m3R?CWi4GMhxHuxaZl2N;Qo`grL-@NTq^48{}>>ulMyHO`DP6rdma`i`uTj9 zcK;b3s6H9`KgX*$wD%>Zr@L#=1R6jq0sOnEpru|@`4CvqbBwcV~u)H815mZ~6j*i13eONuy^f#cLB%J1rYf))Pk*z&BI#Q8>J+y6B4Rjrr><|DA57~v zwyX-~;>HzU>_5C%%0?Pa9mrgZ3f@X8Xhz4yzIG6YC)z9ud$=7x`XC+q5Z5!B5P;)O zYYWdY0#`6AKJUSEUbIPc4pFYR5{)_8x_s0tVvs zLsPcRkwq8#MLrsreN?A}$r4kUjL`GbKV74HW`4!GtC6OjGt~Rz*41yE^ppd_@Q}uu zhqhd)mft&HYVA2_2aaC-LCzm2jZ_3ymOk7X9|Ez^(hjxGNPvHZq^sB-54X7+4M8rn z`jF7PN8+^@0zsUcnAH;CU`FRZiF?bj5t{zZ&hiU2OVUZl)pDJZX^rEiZcbM@DoZQ# zG-&KZcY=x6Q`;&&4}uKMex&P(1=$3qLsM_0^CM<7-Y3YN{jCZc?6CZ?vNeuy+ELY> z{ukfobujxXl;e;dgSt&ydIv|sjUKkl{Hy0(8{}7US4Hr|@nxT>Vrn4K&UbwXy|6P! zcWSu;7jIVK;KxH2Vl|*vF+VNan#7bE+UEZ~JFagKc}A%zr?;CNA6~a08P;)ffLF|V z4zENFi(1foSSze+@~d0A4d`$k2^%SK#S@^;$%EM_J~go8Db+abwciGj7j!5pjHXe9 z1J)Q$*#7wyLEcNomF$r+kQOE0@5`X;1qII>S^B|^FW$c=g7;5984iz~dMQ*3^*!UR z;nY7!Q`<)Jzb&O#CIbf4*KM<)g7W-=>BZfF#QbGyM)-bLXHnh4l>(1uO-!Jp4954{ zjXL9(w$9m4!9YmOVgicCEFg*lGNY+78wm!sQ?w>kV9+JIGE*k|14zYjfRef7(BD?rilQ5cgoU|MvL>aX7rFI{ea!U`c&=tpP2FyIX@Pi7b0cC z7e#oh?hy_0_#q~%ByyXB6x86s!Zkz~-(|K*{bG)NFN0lHR7);43SP!Re2A@WO zEPP-$tgOJ7fO2q=V#NBQLE5k2-=iPGe}=C5Vt00U?r&^r1Cg0$Z;CD6LK+))B1)Cq zWNpum1y^YoGuu!exAC{&M#TpX|60SJwiu3%VWj|u7Xw=i4*Quf!=-2f9u=3}(6`zf_gNHj<$O$=e(H7cccN9Nrf zE156@m;3E1g*8oo%fk5uL-4xU+Xiktf)90b$ACr1^Z4q(iEk>Z!q3K0bdlGR%$IuD#6<9 z>J4jfc{fQ7<^>(Wp-+{WBa3?%_yjcV;O2p3-X!;M%lQYm9MG9QQrm)hlUN&>en*tV z8p8x_q)^|zN2GZ=D^y{(r=%fdo6lt!JEC}9TT$*xMf8fLgT&d!%1mrP&vHW7r@^aQ zfW0_x-8jgM02Mt-bCA@Oql8UI6RaG)y)?iBmAI` zmv8AOvEq(tp_`X7-_Fu^#_Gr;(#+1fHO=Q&%lzEl+|eV`{z0my=0+igcpA5-v<=Pi zQg(boqWk17nX@M{F(83Hj*n0muHYAO=@sEpq8GWOjM^osWE;t^JC__si5=GmA02+G z72E7%B>EP-0>$KMQIyplh%oOntq~BmW#;RZp66pw_yif?EBXy|0uj zs_aoWs{^jzGoLTl_!-|XFx77A&4)HL#K6w%aVnDT=uzrg1X_yw$KH37Ok8IA(|spm z8s;;fSZ%oR@y8f(A6LVss3(+*z`&=83(JK{a&O6T75Onb48v1Hi4lHmF9XS2`i*%_3dn4MG66&%y7{)6_#w2KHa0~!hy9EhftM_ zO#!Qol`ey=xWs^`JV3W8J1?Kly0%}NWXzIEGT)4nBny!#;#Wn(tq;3~D!3%l-COrw zm@BL(&q(Eo^9z?vI@2Dea&U8+YQAn`Lb86bWXH+rD300LCdk)*@XV7ElleM;J_NM&{T8q zTL==r_-N(u{eyyvluIy8wdTF0@C3hr)s3~Uo?k>*R4izE_ju?KO7~W1pHe3;g|}(g z4+wIJyOZNRZIHH04*CSCZ9O8EpUZFAx38esRPm*-X@3!4L+#5JCSfk7q*rBnB38_S;#q4%UXtI(w&8#p)sxACZo~LKHkj`4Ka}0jmUAp zu_4CM>6S?hKar*w>KTv=vlb&=9`?{uw-%v-09+uxm@d&WXGYE;58G5<@9_>Te4LAG zRWKbSz@KP*ks%Cr|5y0rgtFR^71u_BT?X;-clYb+(#NQe@H4fF9CdCtuVkkunS-3? z3uiW5&4|8L=7m?kT$V8|fdrShK~OVS5v{Kc@y$+BtqpBg&W~1zl(LX@C!aHR*#I&8 z?Shbpn9@;}+4Nhu&rhg`)m%)HEHEH2GtxI0{vgxz&t~#sRjNNamvaOiJ^RNeY4ANy zPFY!cKmhRf!n$ca-KLVJ6LzJ_pLMY#?y#5OKYQv_q7#~nHref1ZDm-8|hiQUt-ke z$NM4tKDggr+D*o!uYm7}BI$NBlUFyz%oXvt-J`N1+=Q3QoYZhDyus`E7O=r753i*e zWMJn?CM?)p?Rf@TWFa_ktHnl+;Ma7N%$Ifv z47`240RTLQRCdP=hyx zTqI=^PlW_U$h{E}53C;t1)=W@rK_n!%b&{Fk;4m63L?VF6LVYjPZC^_!WJ`;`~p!r zy~EL4+5v~IY~R-8>> zOGrTT2kGw&Yw&le7}=ADk={cEVo*qVZ-s$*G(jC(u%zNh(>I*+3bG$LG$79vN(h`$ zm+`?_1MZulq>diUpTi!t`-YY@eK>%=2L}W-pv!p`{b@D)vFimIhFc#%N>fUH?Xj+g zQ1v%dGU;=4V*M11(RFVa{lzA*Z)8|vUsTW)S&H+j7~x*!rOfILp~9L+rbpOSd^1^vKiVPBuK2rS0!_(}};5}aHb?QYrLr;-8A25=F0 zZ_LDVHbc*^#_9MjkYCj&_gYtC=D`JlmMLz^^OTGUKAggdlo`qhHc~7;^-CrCsrn2f zVot7;-}7(e+X5(we0Tvc6Mw)XA$}Fu>@29wX@tPtjSbI_j9+SF957Wk`+YiIgW5(W zXZZDPg%w-{+K%kRVhsXUS5{f{Tx+naEIbT_Y_kvPOzbhFN&KiuBA!k!8@H+w(A4)1 zM*le=%KKA$k@Z`)a3p@>=n*ho!N?Q)DG8$WhspqH@n*lZ1KS~_^O1S|@^`3+Q+Y23 zY`^~bj;bF}a9wddV$ zHF^UeMdI@QE0;W+7=)MEUe=+mDP=n zi0=s~u{}GCXGjC0T4?=7kwTcLD|n>LIB4WZTE;d9!E!QMX#tz7soYPRP=$(?aA23hv5@l}FcL=E2ifWkqD;-OItk2in195705`vIRqFVU5 z;EIwqON;>_1oTyZ8%_S2HOkP;QGEgVvwqp!bwn$xgg!X9PJE`DL*J*ap&fh-o2#8Q ztY?)k7o1=z4Qw|0TZkRxZna8=I4wpv?1XaE5w%(qxsKIep4fW>(b2dJ=VK-fepuHF zqfG3*hNzMxhWP~u-Z`D4?tp)hSng%odp3)nA0@3HXmj9nihlhJa<^PA1Gp7afaRv7 zjK-o}?8{%r`Fq-zw`5fmp8XpZh0RP?zYI#RsUQWo*n0;dH>X(JymeijKlCX-uoiS= zOz>aqlU-m$X<115b>dF*(P5|butW`gufhpNADKr}nZJeC@bQ$rWcUS=+iyn8_HSOz zc%-pAOSC&Xra0g@1rVFMt#e}?ANUv8EkI#N=chg6aOPI|%sWTbWhcDvRE3BL`Y*6M z<1weTh0AU_p>C#K2Lm{-dw_pC-%F*nl;!SZ1m<|mjcT0W1y|+%x2}mE`#vs^(M;Xc zG0!O8`}Pp1)DV0!R}nZo_oQ&{3NB%l)WYP-H-Z8#d63bh7UW+9LP5X4Q`og&w|2?9 z>@%jF&#pVqw6R{E76MwJX%%7`X^c^O<((OIR3po|cc_{SfPAZo(Q9E2?Q0IEG+G@o zzoTqLBjYN2ZAR8sR6l!j9a^g3^H)KR_56;3OeMu@?J$S zwc(#sNIFS#X8%LSOQ^XrJvI*}=udJYQ;lGgz1gezk==?Q>vHc3$s;M?>%s7tAyrPt|UeIMq1X^>({?YTmvcObh#NTg@!p z96)6$4xB7e2<@LN+Nwi(_N*lKI_|q)SPMmGJD9sG> zmxsf6ci~4~;h|;T%`!5O@cBr8>)F?jl}W?aUIYp8KJvIa3zZE>F9x&rt3gBVlkI;XXGvN*%N%WmtDdQ^dq- zIPKd+x6Gwz_{GN9u!rDn;~$HiPldgM-f+N50Dh~Pe4T!@x6&6lV1)KpnQ@40x;Qmx zMH}eGB7KJ)Zb@ha$>!*|4QhM^2z$91U<)$r{#@-A1zS2W3k2+?14fSi2jKSid}Lum z>G0rchZrfamsMdUbyE%+GtGvMdzn@C6yM^U6C8*1^x5gC

iz}!8Bnjr>)02KFDlgK7k)SInuRvPVyL;gJ|hWr#D^C*pB{gdp!ny=tEh5 z0}FD72x@os`KUmzZlX?M=I%;$6>rAoOLyj%PF+2vJOyjHA2eE*UO&cBU4qpE4Nj*# zO^f$yzc)c1%hGc>Uh-N+Z2oh1U(i-2BC7L%cQqXQGs#qOg98{!NLzRU2AaG?_6Z7Lf0}eX z&bv~ywsq>F`EFitVy(7I$H6mns$T%Ltd?o2ga(s}NY(G{-JhBxLw3L8JWbot+z* z(bytY`WY8CyV=F_*~yEDpNKm7=q+GG=;2GTy&KhZH!G_q=-zwrkOjdnIwInXN@(Ls7UWV(5G~L>ZEV$4zj9|a0Ogy5SAPv8*dTqb$R&AFjcv zWo-fkqBc+iBK3g;yPu^M$#|ECHJ%zWw|76!*;%i$1^@toK@XzQ!Dur6_#Y#a`5QHT z9ZnMvtr_bTVjFc~8yg!+m=>SyS-$4i=cEt+fk^WfYp^~omlai~EJhh6T zqlr1I3gz?n$*ISWPQtN-X*-*pKnF_JtD`}uyU~Q@Eq&W8U;XME>=*gH2;9(I(UfhpWHmGiJv z1v;gx@7cZsd7p0B-VT>bCB-IG10;NIAT-_S$4kri(?mqQwY((_&S{j~LU|k|)Qjm! z{!d5!`@U^g>D9U#&-*|)vne1tGg1IUQYICN^SAX>YOh}s+xBA0cN(^^YLKTR@zQE+ znRM%Yug39phJZ}qxQy21I8;T2-IH&`lrwjzq;9E)NHt$Q+LC4FS)t=;p`mb#M4RtZ zj`NilfG6Hj?L`@`LILC~aUG9~TB|dm!nFVib$R99M<^S>86m>=VVag^eV^B{*WBNo zvg@u>^l$w~dFcy%_9eP~dn768%$md~M!TbgfAfaDx0PW)w5G@&{9xEX4HZ8+# zj!oNaCK-@d&6GhuTtFEy{HgcM+Z!rAepdZtzwX{rSrO*Z(ANKdii zORhhSUKNAUs(gRpKBs+=1s{n`qd4~YJD8Q8bqzR117(Nx{Z}cOoTq?G>d7mHY%dD` z;iid+i!rICV~uA7OQrfKh@_#v`47Y za6LeJp=|Jbx5!?cF!=21%oZ=J&&P3~M>Nw*i}bh5SwA}tnF6c`{ae`R4yOT^O_yKy zKh}%61CZL^>oPLG1BA%6bBmmYW>QkbM4R`t+&Xd03a)fMO@YC}i2{WRO}kKpmBMTD zXL((ZFwESL<)lkGl=#-p553&}WVgZ4bY?-B*Cv-y04K~Y=V=M?LEeqYW21qIR0obA zKieEy&`>rSDJdvO-`OmU(08d}5;~1{Kkt@^MPu__Jb&)cz3Nw%?e8WwPbDJmTb$tY zTeD^Dx_Q7GcC{5ed@%vh^6Ux(o~6fMrj>aBm52%=$PiVmp`7AqRGrF*xSqb>rDj5M zz))4e_V|gVFR_b{HD6veoI8AE3lOaxy;+ffXTMKx?VtH8ZyxnbR+k4t0!vt?E&kW3 zSD^Z%_n=0v&Qob>($O;H%xp`vsJnV0xW>`Q#6;iin^4uzPeA6s2>>R+m?Qi8xeJW( zXk)*KNaI|5w`Hx-tYNJ&c|rBc!6ei4&SIwn*BNRIhH@;k{G)o6WGH$x;G^@>C91vz zD!ALsJm#clCUpxBwMn&B9cH5)(T2^+i#1`Ran>Rt;p^Ob%e0Ox^y-*6ePdOaNHbLW zygs}j2Ew;#T0_o1u)43C5+x9URuB(wo0B8@z;ElsabZ*x5;QAR0BY611az;`aq>zr z!k~HJuyy&}jJCZG8oo=l=+c#SB5x8ZCKKV?%h@gepBBIYQg`-2qvq^;T*eR2C(Zk{ zb%f!vhTGO8j15Hfj@U4tK*F@9_529*^L|ZKDE)vhl#b)mrSG>pLGD6sEX+cVj|ris zifl$KBBG6hNYQrX^uK25;hZn?C`Tf?YUoB6*G7Lv5T`;UYk`Ph>RPkrdfpwS79w;r?Nuobw0kS#b-|b=K^fwqK3|~zJUNqrZ3g6!1XO)4TwTAt8v{`8?}wR58F^EJ%a=L7Mqv*6gLuPG)sNYqhA3AVk9{ zyu*E;EbUMq)QPkEH`rktQ56Ha3Pn@5>~sm&gxYB9NuEYLS~C;+&>z)Rf+o!0j!>OE zob^lZ&P?Lwtw3tLg?!2MR{!0h8wSx3tF^QT0t!K1$JGTM)a5U3?*CaD79ZrbJOxeb z!#UEmw$uMZfbOz)b}8eT>_Jl9?!By;ubFtKw!UtG>4;{al+v8fnsJU+;7r2wwPqi` zsU>G(47YX}&Pn+xw}5%0poFm~x49=SB9wg}iL0@0im#wm^U2(R-YHB{Fbe*F1=6Pl ze5k4hDG+l9yLPis95gP;>yI^&-ik1SuupAK6_$_2B}$nS84y_<6cK@~{nA<;(Xw*% zU)1*gkP6Y=Z_QFymWVNPt`buu%7`}7_fy;tZV?OpPUFBn%mO}YuWkmWdFE%Ifqws? z%J#ChR?}+>39s~CypqGTxriLEVG2LkVp?k&MG6v@WjWE3{LTj6UIIl9)#ntA+u6Ny zqe--E=?&NCfwr;?`!sGH2;_e><;NQPEB2%Fw!LbRkNpE^NNs;ooF98E?I2-is9rW- zjC)|KDc;cBEXbrSO7*~`Po>L|xirborSt~`Wt3Jq;Nga@j#X{#pY^-!o+Dc0D8D9@ z*mv_|#N<(O8mjw#u+qy-RZsgM$h`O2A>F>}1%Fb|QO`C#JulSL2X%Xg+#t)`ofV7_ zOi<@c=O-bPY~839Mla1IuzLtUc&MA6zFc6$ozAiEj;<1-?}Y4iEJlDU#`S%ibwl6F zFsaK0f0$;_ZPUQu_J0cCA2D`P^nqY3Q)#>+}M z*hfCqX^per4LQX=l1!D_?Z2W5_FYTt6XX`8946!4AI@b)86!Zbc#yS%I+AiP=Q_tSUe&4zpY|9y&9@xjRd3<{UzKhaAFL&SsP&NEb{5@8oQo-FX zw*&p6i1n_KQR;9^B%Js(Pe|SLnk*4x%iYpJXp*9G7?tY31wC>^C{-kh8RIinv}@N@vqK!ot1; z5BWQ=hU0H6+K;mEw&aY+^Wc1;GAr*FkPysCGd3wKjFPwiTVw~TJFEk3d_zPLj)dIR z;AkjXeb{RpjfF(wmOO!0HK(s#-UC9=8i}U-55_Njozy!LCcd?{isYB5*K~(^S%_&Z+SXt7KH$lohdj+d zf1Q9G8FECJRSQv5Ta+iRvx0}m+BtWX2ZQAixp}TwcB->BNp0b?c4qa|3pA8$4(XEht=5Trb=w0-=rFWmLMMZEV?UJO4D>haur^aChXTAv#vF;O5N_4OEO z*QZph&q`HMc^ReCB-2+|#Scsn18de!a|>v@M{wpv661mbNl`plL#^>nLTA@}3~_># zuA+nC?7oY?^cMEIY|XdGy4Np-?KA$+uF*d45L8B$Jm1((pLPipo{<;XhL<%i)`3!& zizSZIS_?p@YtIP(bL`k=nW_aBARv4FipvBpg^Do~@F80GI#e?li{OU`5?(AAY)yE0 zokj9k+m7d%NSv`b)Rb!D^R-WciF8nh9YQ}8$jZg!QkSbcwbaR-1sfmzGU`uG4I_)%;r3ah~ATk+G zhD`Ri@?mb%^P++Qa}Nwzi%y|8N7K}2P#^Sx(GT8oScORptQ#R8E#uhN9!nY$V7;M^ zhdFMwk0et5q|LACUF08ql{?Dza# zFvG94;vwJ^m2?oQREZu0v2(@u_70Jy8rsU3rEjtu#NmiyuFO~5A^Y!l6cPuu=2hHcF*OCuv({XEM(Sr)c_ ze$ub1ibhi{j`E_gX9p3UHXZTYov`?QUdSMoM&>i%~biB#QHh?j9~})?!l|0m~qn ze9ACUb{SNVzg$){$trp*&F-Igewx(V%krpsb?Rm(!w#$wI`?%sj(T3$g)lbmMi|41 z3u^^bd7a9GfAb{F%}779O_)#43xN)IX;V?$8rXI>RSN_Ba?+2hie_l zR!zOi%BNLsS$ln-I$D+6o5f6Z2@5}PDs zaXy;ohtt{M1N(s?jJ8%L`s;9z!i~eX-A0@@j$hl43#p$coq=gywkgkr(k(@1>^$$j z@wQEy?Mn|OKQI=nl=%ww;%>ZDHkS*QOW?yadd1%N7A)oP#N%;QvB4~3PP%JB_dgs) zo|1i^vo7aO`;ATcZ+>j_qqGreFQu;XgI{|I41krbWFs%+#HQ0YjoND#S7SD8CSr-+ z#9VB8G@Q^WZ4q@;`IQwH?hRZtHVH5$AgS&V6%_&x9QI?Krb6l<92V%$^sg_VfXPBc z%rPU7Q+SOF2Km?|$ApLXR??NhQy8nRaen?JpJ=Y8?ZzGQsy(Ac?#MNen}zE<=aRiUkZ z5C}C~RQv50MqPAOTRCFevb0*%M-Eec92bCx9c0Y$J zOvD)(YG$A581fCISVGv?VAr3sd8VKRN4s=^^F8AN0ROSazhG> zHPXi1O9~J=KeYSN6Gz=L(7r0`EpwcMI;J&OB4{dKN$vm^Je0iYnygG!#_X-}DgWs0 z9AfuyOq$_f)0l_XMqvaLoPxZH3cx90!-?dN{PIK{ zE%AodtURS=)shGSr z=TPIc>exZ$#r`9%H0ugut+qp+6DqMF>JJ@f2>`w0o^08?v!QL=c5a2in2Gv8E>di9 z#0?*Q#eyV7k1?@(gz9bQ4C>_4c&8+_NQHa|+x6r=@V5Okppy7X^=P>1nEQ_5G01lm zxwGzAd=w@e?CgK{6>mgEb0f$d;`3~__B^rPlm15RmDXkbHDSus<2(p`&#A;Z1C2gR z)TRU$VL3N%bAd9;Q?yqs{MutzIVMQ_R@u7HY>jV1j87BHq=}RWwO|>A{E$^kyD?f6^mDc;3$$-?);EX2(TP8pJ)qr{^)cr}Uu~ z&*QQF<-9sePJ^#OEn}fo(wfvNiSe3Qr6Z?z|AjT}gt2H2oby4mS3tY=DV1HqwDm8qSA0-Kg+SiIZsbKxkAze;pu<6MXn9asUDSoXxlMrZG8n;^8s#%<%fd z|Bt5k4r*%uzQ6TymFtHR6{QyyAtFtB3j{?$sRBwbN~qGLg#ZCWln5apy@P;&h?LNK z5t7h*3mrnQ2{rWRe4m-$Uzy1ynM_XR?DyV#t=DRXVV!^aS6io3`bSOyzmN~a*B4o| zYprk~+fA9@?a;JLm0jVq6GQR?)#>4AnwO-nFZ6E1#x`c=;0WJO&UTx@!v=HU0G3h>gV89)Q|>R?;5XDeM>40kI;7 zGaP_c0&*Rt#6?4s5!&cQ$gU%>NNLAvMJW}3_T)h;p)?N9O`N94Er9s$9J?1%XVo_z zmH7KlTeoJw(huEUr^Ni87Y!5XSG;x*Y=1;HF$PpxLgX`)#%ONJJnh=q<}+e`a-tL7 z+9vS$H!huG8JgdjEjIbV71CYVcz0wX^w+S`?V%y>w#Bv&n&EX%s#r{7-T*7)+nrjP zbYX|7iE=ed*FS1MW*Yt3`J5l@mvhSz7R^#`H{a28pRc|I)n#Q&NqeWSV$35uFj_Sw@8qA-z055T$_qwPgPuA6%?^$_0i!0N= zj(uMpyZs%-B{~Wd{%*Pp^%Ub9<5b*Mo3;3CD<+<4Y8ShvF%GnHniM{4r&oscUKonFUh6o`bur5i?XZnV*jG1KPnt|)MbADO4~4W zq+LgODW@%ujivm}jVUDNG6D*T>Ld;1tANVAAbR4a+SYm~Ep0|@Y3Bq{HR0iMI_wiM$cz>6f!FfC_9M9R57(K>l`K)i)A<})~n~pL4Tz>+58S_}7 zzhkLKp>9Co^6iVfNMSuNw@I9{({0r5zq-7+d6T5KfhD|z|BQ{+JvA7SUhkeH$6{L( zY6o2<^S1V0WJslKr9fmNs1)pM=iBuor&xc2C+GWv6VfIs1p0b}@qhp7o#9=l{_kpBl0lcO8RwfTT|rcjsXX=PYQS@8sruW}dQYvhZ|0H9Tz5Pg^89Y2Ru&cDaok1VdZ~AOJ%Pe&6 zZ1rIHgyWa=+Ay7XoKRlF+(}X2deAJIQ*YLah0s zOLH&R?K^jeZ>V(2@{0&LukVA?EbULea?TFx%OFWiiZ-jAUm^>M#fWk?=)`_;ER26? zaWVYuo@tV~)64T^=2|lj_9-X*Ud#>1dbB%UhdA|9B}oebNF_fB?}RhRhnvyFGASI- zhO4DtvgNfkC+q=r_6C2Qc;$LWf#pLZHVIFx<|QTCjz!5+(yOEPr$`ar!S3ufuNUb( z47lq2&YK~`S9WMP>>)6l1!U+chS6?0h28TtUlael$sS0?oGUrk@8rr#djD{GxM}LQ zFrVhA1A%z0;!7yx>7`%_hr$uwTxJuK0v5zdnxhSD_~UI8NbN1AVF4#?VHo6Ez1lL5 z=`p5PhSGs42=}niCtLq{&u=c0Ns_9(tv`*p1*UeMpk~4geS2wUDvP z^Xt5B?L)MJr=gbl3b1I{HP_AT_>Ucqxb!O$U3(M2 zO!4*V4Ih616rV>MFL-nD{MmAEjTOw?A8(J>fR!o$H>;zMltsYT_6PWQes>01Dhsj{X31bcN_L+ANQ82lu^2c z91W33AYTxY&Q1hm5-y>6YL#t~C{+@GbeEN?6}FfTa5!7c(ja{WVluCD#^Q-2Lr&=YD~~jg$pc|#}d%BV`P0NF%;}%prVTc)%t9g z4W#ot!GqhE2eUoHG|+Ik)|sxvaV=7HwicD0HRnkF{BF=s2`uY&e54qvGneB zXGqT@7B|n(1}f!yTBGh%CI&^E&+dUVlK#MJ$sb_AQChiA z8nSLJAuVU2C(0(BTcoWpHPJjU@rCYGqH9+I+qyj~fr70BQh$3wF}+I8o@M52*M;Oq-v4yAt}td=x-Hj8LAmaK-`ZEimiE2- z8=WVLd<_=$nh2$pPG3~hv2eHd{9uSL?#6SXLW4w|wVGm3^a{r+ER##2qDnqmKX`CQxe1S)hop}S}2o2%$%q)y{`2;!(hrp-98gzo=o z0d7G}03qP;Oh;m2UmVz4@s*bAiQRU83LN{D#|o!bSt2!7T~0I!l{s%`%_*kp#WS8g z8F(KGHpX^U3k-#-J+n)ZF1-!>+;bc%p;59#S_e}*%gmO3+GwdXe`^oUeidd#?2?1R z>H9$jG{g+zzDov_LyfUIX99uEn`z7hs|*W*a^+jo!Bxi}+MfJ%4V z5`}R2D4Wi~8o?5xM%o9Ig>Lqe7Ob41EZ5aYNet(d&D@s1-oAi_-G0bwNEsp{d%F)5 zi7#u-2Fl(`h=M$OUj%(+(+{z70SiEYF2Ny#>yzFmh;}ZwD%Zm;0_!KBtbHI*G2m~C zP!nMdbuAht>1a7eGJmq+2I8~@}=j261#bW6Y@drs3M!We+HwDy{A`3c;kT@ zP%V$zLNGfRKqlDut8a=4lcbP6^YLZp2cPa7d2_UCp|M2@`IsZ4HZ^%alK706`s>XE zi)>7(ZW=mNaU^kEipzt$^@!WBM}!jfOJ+N)f$6Aicpo;9dTcAy4dvMLn8o;#=7E7B zB-z9Jg~wt1uQx2&3$(`*i{i>!514f1z;Q1O>#oJQ#0<3^h^D-96kiw#u@#g0G4QaI z|DK5moEhYv)UGi>Y1Pwlvf1KSoYXuqYj>yoU~0ONF5|iG^zx6{lm3cV%xVX1L0Z=> ztioPRXhJQA=dr<%hP5*IVQ%2Z;k8eqs%r&sFInvmu06ekDWsB#{gHbSVn8QR#l*aIt3_2|*XJIb zt7YLC*ncfKjNLko^6S`wuIiYD%az(MEQPf4eqJ0|azKkulX2$V9e>}UIfTclyUWT7 zGn{mt4ua{L05zXj&Vga{|Gm=zSK^~l6SsH>ugSFHrFY-A<&==7PQC6p#;dxyWiOel z+rZ~gI-==qs!SZA)1EmlSPjkHPNz?;BCO<&(yM6@z#?WIl>;1?8#2re+#qG{)|K0ttIXM>ajxt5kL(B12EluYhz3j#eb{Et`Z-7MQffmG;yWgu%HWY=1 zOkhbQGspY!%<)}$Wz@v;MC^(sUgt8?ZnF(tjEF4@Jiua|h0r{;jYA@#G1PArjjga= zYp&dXTazQfYo5))X=60f4K6G7UQT=f2kZZLaZ z%Q^WD7fx?3uplMR-0M9juRMV-jymj_EBeG_Kr{uG%q_{gG2FY+?lXxiKn}@TIsAm(2Jz9 zW71}@JL}@}Q>P3QUOXPG;XVWM``^VxYG#UgG&XK82!o7UklO&clf+> zSxkNbbwYTS>T}d@dY@lc`5T;3&)HZpX7*lG&UyU_U!{FQY{%m=8RvDO?3LQsy=1Mk zQEi^|a277B;D|^U#HMX==@&4plko;Ol)R>P_!CIO+~%xXQ^BK^#(}m-+du&#KN43+ z=soG^p{?cHrQ#yAkl8VRYTOQ4r-d{D}1Sf(`{WZV-z{nUfB@!l;l{@gONY3j9i zoAHtlX(f~gx;{I+L>{0-$F#jk`8OqCtE5MzG?cfzW>z)lroXcq5la-01 z(k`^1*lZ$ZdC?OXLuFFbrvlEmt6j&8klwRFfWm$Ff`&r;ps4g7@}~ZSn5k06`dwu0 zUhUH=Nonc3Ofe(w20y^RIV83=XfMZOF96ffk@ZND>=S9WooR(zYQ@C68Fkc7>UodC zLVi%;65TE68c(>Pj8m9l-!v;!p)cuw()S@(#n}58BJufAQL<7WVwwxsXeiGB-?PKJ zA3qaluP=08_C3#SXJEu9wX^_FR&%lnKozS6v_WYsq6}$FcGvsRhS#OrbYz^vGF&;o zSvrm1DNd`qA22w}BTCOe0987L7Mqs{18!5tvl(~A07}2wLU9w^((`=#)YR>atBO$E zv|&`g*S-QfjrY3<#-L&b8hY`6JAlwKz&Lm33(tjn$}LcF4wJLRSz5l6CWOw?#dJNe@he)tZ`glIv5syjbh(!T_@cC|pz*s||7-pG z&+I1xiqKZ^@dwA*W`9T#SL2Ioj2!KQUsXkYMeNVoz4zx|u2SFsTKOl6)m>@8;Z{f} zs4-P3V1B+BZnVjp;&v}VCUmiX5!nWsWYC{*64O)FpDDAepW5`nU5$v%&`L}HgD*;} zv)Y+y5Syp$P?E+K8t)8^n0Cbo#l(QKwhNd6ff@)_yPE<$Vp{pQhL_roO}e|Oc3q^o zk@R{qhH%+3mX7d30|`HMDG1cwLj%n@P4GF%Ng~%GaKCnx~jI6m2@2F zP`6{>Q?#y37LBud+hF)K^pVx%b$Y%0^(9e4f(l>Uo3Kw$9)Ov?JX-ql-pV zRCM5jf)xW_XSD_qFDEH9ThtCQ#{P#HiN|6wSQQm0J1OaMaWBJF4nJU{NnEUjx~v}m zRdv&kUc35@!RqOC1wHRwM_AeI?^-CIE^ee>~ejuT1+lmTCt05NT<@v3gV{veUJ z_g-Id@85b9Jt%QvwI#!?TZxY&F?+S$%C$3#r&#tIFWVI;*Nw%jo*G7-^gUal`f61T zW*+k{*W)XjaX(F*MQpi7O*ZbJL1@R*f67^y(bFItv$wcf3Z(8@Ru%*4T#&Es?Z)nmZB!Z@3jhV%D?`3(mJwuVBp(!G&|$M(7wn zsi>Y6x}cW4@c!VQJMKX8(xwB|iA*vjm`huXD}&m7w5q1=D-{v*dkrc(d@3a!4Gpt; zHY@{(Ik*C2#N3I;6CY}jBjlb3-AO{jeso^d=hn=-ykd7`kXAW;Z6=n#vb{iugd3&< zxlV^sJ^Xz)Cpx;^u4E`#GrqCqi3W-0k#Mv+@zOP%{ZXa*5lS-Y