Compare commits
15 Commits
fed445b171
...
branch-bla
Author | SHA1 | Date | |
---|---|---|---|
a933487ce0 | |||
5cec300e58 | |||
00146b2e40 | |||
2e1dbddba6 | |||
ba5e1e6fe4 | |||
a64a558f2f | |||
99099bf78f | |||
5d94363715 | |||
0c8db615eb | |||
afb39ae3cc | |||
46bece8209 | |||
3e3d9bbcff | |||
ff52114f9b | |||
efd3302645 | |||
a7f060c3eb |
43
.github/workflows/static.yml
vendored
43
.github/workflows/static.yml
vendored
@ -1,43 +0,0 @@
|
||||
# Simple workflow for deploying static content to GitHub Pages
|
||||
name: Deploy static content to Pages
|
||||
|
||||
on:
|
||||
# Runs on pushes targeting the default branch
|
||||
push:
|
||||
branches: ["master"]
|
||||
|
||||
# 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 only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
|
||||
# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
|
||||
concurrency:
|
||||
group: "pages"
|
||||
cancel-in-progress: false
|
||||
|
||||
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@v4
|
||||
- name: Setup Pages
|
||||
uses: actions/configure-pages@v5
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-pages-artifact@v3
|
||||
with:
|
||||
# Upload entire repository
|
||||
path: '.'
|
||||
- name: Deploy to GitHub Pages
|
||||
id: deployment
|
||||
uses: actions/deploy-pages@v4
|
@ -14,11 +14,7 @@ android {
|
||||
buildConfigField "String", "APP_BUILD_TIME", '"' + (new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ", Locale.ROOT).format(new Date())) + '"'
|
||||
}
|
||||
|
||||
buildFeatures {
|
||||
buildConfig = true
|
||||
}
|
||||
|
||||
compileSdkVersion 30
|
||||
compileSdkVersion 29
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
|
@ -1,8 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:versionCode="57"
|
||||
android:versionName="10.1.1">
|
||||
android:versionCode="55"
|
||||
android:versionName="10.0">
|
||||
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||
|
||||
|
@ -58,9 +58,6 @@ import java.util.List;
|
||||
* When an AprilTag in the TagLibrary is detected, the SDK provides location and orientation of the robot, relative to the field origin.
|
||||
* This information is provided in the "robotPose" member of the returned "detection".
|
||||
*
|
||||
* To learn about the Field Coordinate System that is defined for FTC (and used by this OpMode), see the FTC-DOCS link below:
|
||||
* https://ftc-docs.firstinspires.org/en/latest/game_specific_resources/field_coordinate_system/field-coordinate-system.html
|
||||
*
|
||||
* Use Android Studio to Copy this Class, and Paste it into your team's code folder with a new name.
|
||||
* Remove or comment out the @Disabled line to add this OpMode to the Driver Station OpMode list.
|
||||
*/
|
||||
|
@ -1,191 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2024 Phil Malone
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.firstinspires.ftc.robotcontroller.external.samples;
|
||||
|
||||
import android.util.Size;
|
||||
|
||||
import com.qualcomm.robotcore.eventloop.opmode.Disabled;
|
||||
import com.qualcomm.robotcore.eventloop.opmode.LinearOpMode;
|
||||
import com.qualcomm.robotcore.eventloop.opmode.TeleOp;
|
||||
import com.qualcomm.robotcore.util.SortOrder;
|
||||
|
||||
import org.firstinspires.ftc.robotcore.external.Telemetry;
|
||||
import org.firstinspires.ftc.robotcore.external.hardware.camera.WebcamName;
|
||||
import org.firstinspires.ftc.vision.VisionPortal;
|
||||
import org.firstinspires.ftc.vision.opencv.ColorBlobLocatorProcessor;
|
||||
import org.firstinspires.ftc.vision.opencv.ColorRange;
|
||||
import org.firstinspires.ftc.vision.opencv.ImageRegion;
|
||||
import org.opencv.core.RotatedRect;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/*
|
||||
* This OpMode illustrates how to use a video source (camera) to locate specifically colored regions
|
||||
*
|
||||
* Unlike a "color sensor" which determines the color of an object in the field of view, this "color locator"
|
||||
* will search the Region Of Interest (ROI) in a camera image, and find any "blobs" of color that match the requested color range.
|
||||
* These blobs can be further filtered and sorted to find the one most likely to be the item the user is looking for.
|
||||
*
|
||||
* To perform this function, a VisionPortal runs a ColorBlobLocatorProcessor process.
|
||||
* The ColorBlobLocatorProcessor process is created first, and then the VisionPortal is built to use this process.
|
||||
* The ColorBlobLocatorProcessor analyses the ROI and locates pixels that match the ColorRange to form a "mask".
|
||||
* The matching pixels are then collected into contiguous "blobs" of pixels. The outer boundaries of these blobs are called its "contour".
|
||||
* For each blob, the process then creates the smallest possible rectangle "boxFit" that will fully encase the contour.
|
||||
* The user can then call getBlobs() to retrieve the list of Blobs, where each Blob contains the contour and the boxFit data.
|
||||
* Note: The default sort order for Blobs is ContourArea, in descending order, so the biggest contours are listed first.
|
||||
*
|
||||
* To aid the user, a colored boxFit rectangle is drawn on the camera preview to show the location of each Blob
|
||||
* The original Blob contour can also be added to the preview. This is helpful when configuring the ColorBlobLocatorProcessor parameters.
|
||||
*
|
||||
* Use Android Studio to Copy this Class, and Paste it into your team's code folder with a new name.
|
||||
* Remove or comment out the @Disabled line to add this OpMode to the Driver Station OpMode list
|
||||
*/
|
||||
|
||||
@Disabled
|
||||
@TeleOp(name = "Concept: Vision Color-Locator", group = "Concept")
|
||||
public class ConceptVisionColorLocator extends LinearOpMode
|
||||
{
|
||||
@Override
|
||||
public void runOpMode()
|
||||
{
|
||||
/* Build a "Color Locator" vision processor based on the ColorBlobLocatorProcessor class.
|
||||
* - Specify the color range you are looking for. You can use a predefined color, or create you own color range
|
||||
* .setTargetColorRange(ColorRange.BLUE) // use a predefined color match
|
||||
* Available predefined colors are: RED, BLUE YELLOW GREEN
|
||||
* .setTargetColorRange(new ColorRange(ColorSpace.YCrCb, // or define your own color match
|
||||
* new Scalar( 32, 176, 0),
|
||||
* new Scalar(255, 255, 132)))
|
||||
*
|
||||
* - Focus the color locator by defining a RegionOfInterest (ROI) which you want to search.
|
||||
* This can be the entire frame, or a sub-region defined using:
|
||||
* 1) standard image coordinates or 2) a normalized +/- 1.0 coordinate system.
|
||||
* Use one form of the ImageRegion class to define the ROI.
|
||||
* ImageRegion.entireFrame()
|
||||
* ImageRegion.asImageCoordinates(50, 50, 150, 150) 100x100 pixel square near the upper left corner
|
||||
* ImageRegion.asUnityCenterCoordinates(-0.5, 0.5, 0.5, -0.5) 50% width/height square centered on screen
|
||||
*
|
||||
* - Define which contours are included.
|
||||
* You can get ALL the contours, or you can skip any contours that are completely inside another contour.
|
||||
* .setContourMode(ColorBlobLocatorProcessor.ContourMode.ALL_FLATTENED_HIERARCHY) // return all contours
|
||||
* .setContourMode(ColorBlobLocatorProcessor.ContourMode.EXTERNAL_ONLY) // exclude contours inside other contours
|
||||
* note: EXTERNAL_ONLY helps to avoid bright reflection spots from breaking up areas of solid color.
|
||||
*
|
||||
* - turn the display of contours ON or OFF. Turning this on helps debugging but takes up valuable CPU time.
|
||||
* .setDrawContours(true)
|
||||
*
|
||||
* - include any pre-processing of the image or mask before looking for Blobs.
|
||||
* There are some extra processing you can include to improve the formation of blobs. Using these features requires
|
||||
* an understanding of how they may effect the final blobs. The "pixels" argument sets the NxN kernel size.
|
||||
* .setBlurSize(int pixels) Blurring an image helps to provide a smooth color transition between objects, and smoother contours.
|
||||
* The higher the number of pixels, the more blurred the image becomes.
|
||||
* Note: Even "pixels" values will be incremented to satisfy the "odd number" requirement.
|
||||
* Blurring too much may hide smaller features. A "pixels" size of 5 is good for a 320x240 image.
|
||||
* .setErodeSize(int pixels) Erosion removes floating pixels and thin lines so that only substantive objects remain.
|
||||
* Erosion can grow holes inside regions, and also shrink objects.
|
||||
* "pixels" in the range of 2-4 are suitable for low res images.
|
||||
* .setDilateSize(int pixels) Dilation makes objects more visible by filling in small holes, making lines appear thicker,
|
||||
* and making filled shapes appear larger. Dilation is useful for joining broken parts of an
|
||||
* object, such as when removing noise from an image.
|
||||
* "pixels" in the range of 2-4 are suitable for low res images.
|
||||
*/
|
||||
ColorBlobLocatorProcessor colorLocator = new ColorBlobLocatorProcessor.Builder()
|
||||
.setTargetColorRange(ColorRange.BLUE) // use a predefined color match
|
||||
.setContourMode(ColorBlobLocatorProcessor.ContourMode.EXTERNAL_ONLY) // exclude blobs inside blobs
|
||||
.setRoi(ImageRegion.asUnityCenterCoordinates(-0.5, 0.5, 0.5, -0.5)) // search central 1/4 of camera view
|
||||
.setDrawContours(true) // Show contours on the Stream Preview
|
||||
.setBlurSize(5) // Smooth the transitions between different colors in image
|
||||
.build();
|
||||
|
||||
/*
|
||||
* Build a vision portal to run the Color Locator process.
|
||||
*
|
||||
* - Add the colorLocator process created above.
|
||||
* - Set the desired video resolution.
|
||||
* Since a high resolution will not improve this process, choose a lower resolution that is
|
||||
* supported by your camera. This will improve overall performance and reduce latency.
|
||||
* - Choose your video source. This may be
|
||||
* .setCamera(hardwareMap.get(WebcamName.class, "Webcam 1")) ..... for a webcam
|
||||
* or
|
||||
* .setCamera(BuiltinCameraDirection.BACK) ... for a Phone Camera
|
||||
*/
|
||||
VisionPortal portal = new VisionPortal.Builder()
|
||||
.addProcessor(colorLocator)
|
||||
.setCameraResolution(new Size(320, 240))
|
||||
.setCamera(hardwareMap.get(WebcamName.class, "Webcam 1"))
|
||||
.build();
|
||||
|
||||
telemetry.setMsTransmissionInterval(50); // Speed up telemetry updates, Just use for debugging.
|
||||
telemetry.setDisplayFormat(Telemetry.DisplayFormat.MONOSPACE);
|
||||
|
||||
// WARNING: To be able to view the stream preview on the Driver Station, this code runs in INIT mode.
|
||||
while (opModeIsActive() || opModeInInit())
|
||||
{
|
||||
telemetry.addData("preview on/off", "... Camera Stream\n");
|
||||
|
||||
// Read the current list
|
||||
List<ColorBlobLocatorProcessor.Blob> blobs = colorLocator.getBlobs();
|
||||
|
||||
/*
|
||||
* The list of Blobs can be filtered to remove unwanted Blobs.
|
||||
* Note: All contours will be still displayed on the Stream Preview, but only those that satisfy the filter
|
||||
* conditions will remain in the current list of "blobs". Multiple filters may be used.
|
||||
*
|
||||
* Use any of the following filters.
|
||||
*
|
||||
* ColorBlobLocatorProcessor.Util.filterByArea(minArea, maxArea, blobs);
|
||||
* A Blob's area is the number of pixels contained within the Contour. Filter out any that are too big or small.
|
||||
* Start with a large range and then refine the range based on the likely size of the desired object in the viewfinder.
|
||||
*
|
||||
* ColorBlobLocatorProcessor.Util.filterByDensity(minDensity, maxDensity, blobs);
|
||||
* A blob's density is an indication of how "full" the contour is.
|
||||
* If you put a rubber band around the contour you would get the "Convex Hull" of the contour.
|
||||
* The density is the ratio of Contour-area to Convex Hull-area.
|
||||
*
|
||||
* ColorBlobLocatorProcessor.Util.filterByAspectRatio(minAspect, maxAspect, blobs);
|
||||
* A blob's Aspect ratio is the ratio of boxFit long side to short side.
|
||||
* A perfect Square has an aspect ratio of 1. All others are > 1
|
||||
*/
|
||||
ColorBlobLocatorProcessor.Util.filterByArea(50, 20000, blobs); // filter out very small blobs.
|
||||
|
||||
/*
|
||||
* The list of Blobs can be sorted using the same Blob attributes as listed above.
|
||||
* No more than one sort call should be made. Sorting can use ascending or descending order.
|
||||
* ColorBlobLocatorProcessor.Util.sortByArea(SortOrder.DESCENDING, blobs); // Default
|
||||
* ColorBlobLocatorProcessor.Util.sortByDensity(SortOrder.DESCENDING, blobs);
|
||||
* ColorBlobLocatorProcessor.Util.sortByAspectRatio(SortOrder.DESCENDING, blobs);
|
||||
*/
|
||||
|
||||
telemetry.addLine(" Area Density Aspect Center");
|
||||
|
||||
// Display the size (area) and center location for each Blob.
|
||||
for(ColorBlobLocatorProcessor.Blob b : blobs)
|
||||
{
|
||||
RotatedRect boxFit = b.getBoxFit();
|
||||
telemetry.addLine(String.format("%5d %4.2f %5.2f (%3d,%3d)",
|
||||
b.getContourArea(), b.getDensity(), b.getAspectRatio(), (int) boxFit.center.x, (int) boxFit.center.y));
|
||||
}
|
||||
|
||||
telemetry.update();
|
||||
sleep(50);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,136 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2024 Phil Malone
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.firstinspires.ftc.robotcontroller.external.samples;
|
||||
|
||||
import android.graphics.Color;
|
||||
import android.util.Size;
|
||||
|
||||
import com.qualcomm.robotcore.eventloop.opmode.Disabled;
|
||||
import com.qualcomm.robotcore.eventloop.opmode.LinearOpMode;
|
||||
import com.qualcomm.robotcore.eventloop.opmode.TeleOp;
|
||||
|
||||
import org.firstinspires.ftc.robotcore.external.hardware.camera.WebcamName;
|
||||
import org.firstinspires.ftc.vision.VisionPortal;
|
||||
import org.firstinspires.ftc.vision.opencv.ImageRegion;
|
||||
import org.firstinspires.ftc.vision.opencv.PredominantColorProcessor;
|
||||
|
||||
/*
|
||||
* This OpMode illustrates how to use a video source (camera) as a color sensor
|
||||
*
|
||||
* A "color sensor" will typically determine the color of the object that it is pointed at.
|
||||
*
|
||||
* This sample performs the same function, except it uses a video camera to inspect an object or scene.
|
||||
* The user may choose to inspect all, or just a Region of Interest (ROI), of the active camera view.
|
||||
* The user must also provide a list of "acceptable colors" (Swatches) from which the closest matching color will be selected.
|
||||
*
|
||||
* To perform this function, a VisionPortal runs a PredominantColorProcessor process.
|
||||
* The PredominantColorProcessor process is created first, and then the VisionPortal is built to use this process.
|
||||
* The PredominantColorProcessor analyses the ROI and splits the colored pixels into several color-clusters.
|
||||
* The largest of these clusters is then considered to be the "Predominant Color"
|
||||
* The process then matches the Predominant Color with the closest Swatch and returns that match.
|
||||
*
|
||||
* To aid the user, a colored rectangle is drawn on the camera preview to show the RegionOfInterest,
|
||||
* The Predominant Color is used to paint the rectangle border, so the user can verify that the color is reasonable.
|
||||
*
|
||||
* Use Android Studio to Copy this Class, and Paste it into your team's code folder with a new name.
|
||||
* Remove or comment out the @Disabled line to add this OpMode to the Driver Station OpMode list
|
||||
*/
|
||||
|
||||
@Disabled
|
||||
@TeleOp(name = "Concept: Vision Color-Sensor", group = "Concept")
|
||||
public class ConceptVisionColorSensor extends LinearOpMode
|
||||
{
|
||||
@Override
|
||||
public void runOpMode()
|
||||
{
|
||||
/* Build a "Color Sensor" vision processor based on the PredominantColorProcessor class.
|
||||
*
|
||||
* - Focus the color sensor by defining a RegionOfInterest (ROI) which you want to inspect.
|
||||
* This can be the entire frame, or a sub-region defined using:
|
||||
* 1) standard image coordinates or 2) a normalized +/- 1.0 coordinate system.
|
||||
* Use one form of the ImageRegion class to define the ROI.
|
||||
* ImageRegion.entireFrame()
|
||||
* ImageRegion.asImageCoordinates(50, 50, 150, 150) 100x100 pixel square near the upper left corner
|
||||
* ImageRegion.asUnityCenterCoordinates(-0.1, 0.1, 0.1, -0.1) 10% width/height square centered on screen
|
||||
*
|
||||
* - Set the list of "acceptable" color swatches (matches).
|
||||
* Only colors that you assign here will be returned.
|
||||
* If you know the sensor will be pointing to one of a few specific colors, enter them here.
|
||||
* Or, if the sensor may be pointed randomly, provide some additional colors that may match the surrounding.
|
||||
* Possible choices are:
|
||||
* RED, ORANGE, YELLOW, GREEN, CYAN, BLUE, PURPLE, MAGENTA, BLACK, WHITE;
|
||||
*
|
||||
* Note that in the example shown below, only some of the available colors are included.
|
||||
* This will force any other colored region into one of these colors.
|
||||
* eg: Green may be reported as YELLOW, as this may be the "closest" match.
|
||||
*/
|
||||
PredominantColorProcessor colorSensor = new PredominantColorProcessor.Builder()
|
||||
.setRoi(ImageRegion.asUnityCenterCoordinates(-0.1, 0.1, 0.1, -0.1))
|
||||
.setSwatches(
|
||||
PredominantColorProcessor.Swatch.RED,
|
||||
PredominantColorProcessor.Swatch.BLUE,
|
||||
PredominantColorProcessor.Swatch.YELLOW,
|
||||
PredominantColorProcessor.Swatch.BLACK,
|
||||
PredominantColorProcessor.Swatch.WHITE)
|
||||
.build();
|
||||
|
||||
/*
|
||||
* Build a vision portal to run the Color Sensor process.
|
||||
*
|
||||
* - Add the colorSensor process created above.
|
||||
* - Set the desired video resolution.
|
||||
* Since a high resolution will not improve this process, choose a lower resolution that is
|
||||
* supported by your camera. This will improve overall performance and reduce latency.
|
||||
* - Choose your video source. This may be
|
||||
* .setCamera(hardwareMap.get(WebcamName.class, "Webcam 1")) ..... for a webcam
|
||||
* or
|
||||
* .setCamera(BuiltinCameraDirection.BACK) ... for a Phone Camera
|
||||
*/
|
||||
VisionPortal portal = new VisionPortal.Builder()
|
||||
.addProcessor(colorSensor)
|
||||
.setCameraResolution(new Size(320, 240))
|
||||
.setCamera(hardwareMap.get(WebcamName.class, "Webcam 1"))
|
||||
.build();
|
||||
|
||||
telemetry.setMsTransmissionInterval(50); // Speed up telemetry updates, Just use for debugging.
|
||||
|
||||
// WARNING: To be able to view the stream preview on the Driver Station, this code runs in INIT mode.
|
||||
while (opModeIsActive() || opModeInInit())
|
||||
{
|
||||
telemetry.addData("DS preview on/off", "3 dots, Camera Stream\n");
|
||||
|
||||
// Request the most recent color analysis.
|
||||
// This will return the closest matching colorSwatch and the predominant RGB color.
|
||||
// Note: to take actions based on the detected color, simply use the colorSwatch in a comparison or switch.
|
||||
// eg:
|
||||
// if (result.closestSwatch == PredominantColorProcessor.Swatch.RED) {... some code ...}
|
||||
PredominantColorProcessor.Result result = colorSensor.getAnalysis();
|
||||
|
||||
// Display the Color Sensor result.
|
||||
telemetry.addData("Best Match:", result.closestSwatch);
|
||||
telemetry.addLine(String.format("R %3d, G %3d, B %3d", Color.red(result.rgb), Color.green(result.rgb), Color.blue(result.rgb)));
|
||||
telemetry.update();
|
||||
|
||||
sleep(20);
|
||||
}
|
||||
}
|
||||
}
|
27
TeamCode/src/main/java/ServoPractice.java
Normal file
27
TeamCode/src/main/java/ServoPractice.java
Normal file
@ -0,0 +1,27 @@
|
||||
import com.qualcomm.robotcore.eventloop.opmode.OpMode;
|
||||
import com.qualcomm.robotcore.hardware.DcMotor;
|
||||
import com.qualcomm.robotcore.hardware.Servo;
|
||||
|
||||
public class ServoPractice extends OpMode {
|
||||
//servo
|
||||
Servo test_servo;
|
||||
|
||||
|
||||
public void init(){
|
||||
//hw map
|
||||
test_servo = hardwareMap.get(Servo.class, "test_servo");
|
||||
}
|
||||
public void loop(){
|
||||
//make it move
|
||||
test_servo.setPosition(0);
|
||||
try {
|
||||
Thread.sleep(500);
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
test_servo.setPosition(1);
|
||||
}
|
||||
public void stop(){
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,122 @@
|
||||
package org.firstinspires.ftc.teamcode;
|
||||
|
||||
import static org.firstinspires.ftc.teamcode.PedroConstants.BACK_LEFT_MOTOR;
|
||||
import static org.firstinspires.ftc.teamcode.PedroConstants.BACK_RIGHT_MOTOR;
|
||||
import static org.firstinspires.ftc.teamcode.PedroConstants.FRONT_LEFT_MOTOR;
|
||||
import static org.firstinspires.ftc.teamcode.PedroConstants.FRONT_RIGHT_MOTOR;
|
||||
|
||||
import com.acmerobotics.dashboard.FtcDashboard;
|
||||
import com.acmerobotics.dashboard.config.Config;
|
||||
import com.acmerobotics.dashboard.telemetry.MultipleTelemetry;
|
||||
import com.qualcomm.robotcore.eventloop.opmode.Autonomous;
|
||||
import com.qualcomm.robotcore.eventloop.opmode.OpMode;
|
||||
import com.qualcomm.robotcore.hardware.DcMotor;
|
||||
import com.qualcomm.robotcore.hardware.DcMotorEx;
|
||||
|
||||
import org.firstinspires.ftc.robotcore.external.Telemetry;
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.follower.Follower;
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.localization.Pose;
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.pathGeneration.BezierCurve;
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.pathGeneration.BezierLine;
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.pathGeneration.PathChain;
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.pathGeneration.Point;
|
||||
|
||||
/**
|
||||
* This is the Circle autonomous OpMode. It runs the robot in a PathChain that's actually not quite
|
||||
* a circle, but some Bezier curves that have control points set essentially in a square. However,
|
||||
* it turns enough to tune your centripetal force correction and some of your heading. Some lag in
|
||||
* heading is to be expected.
|
||||
*
|
||||
* @author Anyi Lin - 10158 Scott's Bots
|
||||
* @author Aaron Yang - 10158 Scott's Bots
|
||||
* @author Harrison Womack - 10158 Scott's Bots
|
||||
* @version 1.0, 3/12/2024
|
||||
*/
|
||||
@Config
|
||||
@Autonomous(name = "AutoExample", group = "Autonomous Pathing Tuning")
|
||||
public class AutoExample extends OpMode {
|
||||
private Telemetry telemetryA;
|
||||
|
||||
private Follower follower;
|
||||
|
||||
private PathChain path;
|
||||
|
||||
private final Pose startPose = new Pose(12.0, 11, 90);
|
||||
|
||||
/**
|
||||
* This initializes the Follower and creates the PathChain for the "circle". Additionally, this
|
||||
* initializes the FTC Dashboard telemetry.
|
||||
*/
|
||||
@Override
|
||||
public void init() {
|
||||
follower = new Follower(hardwareMap);
|
||||
|
||||
follower.setMaxPower(.6);
|
||||
|
||||
follower.setStartingPose(startPose);
|
||||
|
||||
path = follower.pathBuilder()
|
||||
.addPath(
|
||||
// Line 1
|
||||
new BezierLine(
|
||||
new Point(12.804, 11.223, Point.CARTESIAN),
|
||||
new Point(12.804, 42.362, Point.CARTESIAN)
|
||||
)
|
||||
)
|
||||
.setTangentHeadingInterpolation()
|
||||
.addPath(
|
||||
// Line 2
|
||||
new BezierCurve(
|
||||
new Point(12.804, 42.362, Point.CARTESIAN),
|
||||
new Point(11.381, 57.379, Point.CARTESIAN),
|
||||
new Point(31.614, 56.588, Point.CARTESIAN)
|
||||
)
|
||||
)
|
||||
.setTangentHeadingInterpolation()
|
||||
.addPath(
|
||||
// Line 3
|
||||
new BezierLine(
|
||||
new Point(31.614, 56.588, Point.CARTESIAN),
|
||||
new Point(51.214, 56.746, Point.CARTESIAN)
|
||||
)
|
||||
)
|
||||
.setTangentHeadingInterpolation()
|
||||
.addPath(
|
||||
// Line 4
|
||||
new BezierCurve(
|
||||
new Point(51.214, 56.746, Point.CARTESIAN),
|
||||
new Point(64.334, 58.643, Point.CARTESIAN),
|
||||
new Point(61.172, 45.524, Point.CARTESIAN)
|
||||
)
|
||||
)
|
||||
.setTangentHeadingInterpolation()
|
||||
.addPath(
|
||||
// Line 5
|
||||
new BezierCurve(
|
||||
new Point(61.172, 45.524, Point.CARTESIAN),
|
||||
new Point(36.198, 26.239, Point.CARTESIAN),
|
||||
new Point(19.759, 11.065, Point.CARTESIAN)
|
||||
)
|
||||
)
|
||||
.setTangentHeadingInterpolation()
|
||||
.build();
|
||||
|
||||
follower.followPath(path);
|
||||
|
||||
telemetryA = new MultipleTelemetry(this.telemetry, FtcDashboard.getInstance().getTelemetry());
|
||||
telemetryA.update();
|
||||
}
|
||||
|
||||
/**
|
||||
* This runs the OpMode, updating the Follower as well as printing out the debug statements to
|
||||
* the Telemetry, as well as the FTC Dashboard.
|
||||
*/
|
||||
@Override
|
||||
public void loop() {
|
||||
follower.update();
|
||||
if (follower.atParametricEnd()) {
|
||||
follower.followPath(path);
|
||||
}
|
||||
follower.telemetryDebug(telemetryA);
|
||||
}
|
||||
}
|
@ -0,0 +1,95 @@
|
||||
package org.firstinspires.ftc.teamcode;
|
||||
|
||||
import com.acmerobotics.dashboard.FtcDashboard;
|
||||
import com.acmerobotics.dashboard.config.Config;
|
||||
import com.acmerobotics.dashboard.telemetry.MultipleTelemetry;
|
||||
import com.qualcomm.robotcore.eventloop.opmode.Autonomous;
|
||||
import com.qualcomm.robotcore.eventloop.opmode.OpMode;
|
||||
|
||||
import org.firstinspires.ftc.robotcore.external.Telemetry;
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.follower.Follower;
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.localization.Pose;
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.pathGeneration.BezierCurve;
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.pathGeneration.BezierLine;
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.pathGeneration.PathChain;
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.pathGeneration.Point;
|
||||
|
||||
/**
|
||||
* This is the Circle autonomous OpMode. It runs the robot in a PathChain that's actually not quite
|
||||
* a circle, but some Bezier curves that have control points set essentially in a square. However,
|
||||
* it turns enough to tune your centripetal force correction and some of your heading. Some lag in
|
||||
* heading is to be expected.
|
||||
*
|
||||
* @author Anyi Lin - 10158 Scott's Bots
|
||||
* @author Aaron Yang - 10158 Scott's Bots
|
||||
* @author Harrison Womack - 10158 Scott's Bots
|
||||
* @version 1.0, 3/12/2024
|
||||
*/
|
||||
@Config
|
||||
@Autonomous(name = "AutoExampleTwo", group = "Autonomous Pathing Tuning")
|
||||
public class AutoExampleTwo extends OpMode {
|
||||
private Telemetry telemetryA;
|
||||
|
||||
private Follower follower;
|
||||
|
||||
private PathChain path;
|
||||
|
||||
private final Pose startPose = new Pose(10.0, 40, 90);
|
||||
|
||||
/**
|
||||
* This initializes the Follower and creates the PathChain for the "circle". Additionally, this
|
||||
* initializes the FTC Dashboard telemetry.
|
||||
*/
|
||||
@Override
|
||||
public void init() {
|
||||
follower = new Follower(hardwareMap);
|
||||
|
||||
follower.setMaxPower(.4);
|
||||
|
||||
follower.setStartingPose(startPose);
|
||||
|
||||
path = follower.pathBuilder()
|
||||
.addPath(
|
||||
// Line 1
|
||||
new BezierLine(
|
||||
new Point(10.000, 40.000, Point.CARTESIAN),
|
||||
new Point(60.000, 40.000, Point.CARTESIAN)
|
||||
)
|
||||
)
|
||||
.setConstantHeadingInterpolation(Math.toRadians(90))
|
||||
.addPath(
|
||||
// Line 2
|
||||
new BezierLine(
|
||||
new Point(60.000, 40.000, Point.CARTESIAN),
|
||||
new Point(60.000, 25.000, Point.CARTESIAN)
|
||||
)
|
||||
)
|
||||
.setConstantHeadingInterpolation(Math.toRadians(90))
|
||||
.addPath(
|
||||
// Line 3
|
||||
new BezierLine(
|
||||
new Point(60.000, 25.000, Point.CARTESIAN),
|
||||
new Point(10.000, 25.000, Point.CARTESIAN)
|
||||
)
|
||||
)
|
||||
.setConstantHeadingInterpolation(Math.toRadians(90)).build();
|
||||
|
||||
follower.followPath(path);
|
||||
|
||||
telemetryA = new MultipleTelemetry(this.telemetry, FtcDashboard.getInstance().getTelemetry());
|
||||
telemetryA.update();
|
||||
}
|
||||
|
||||
/**
|
||||
* This runs the OpMode, updating the Follower as well as printing out the debug statements to
|
||||
* the Telemetry, as well as the FTC Dashboard.
|
||||
*/
|
||||
@Override
|
||||
public void loop() {
|
||||
follower.update();
|
||||
if (follower.atParametricEnd()) {
|
||||
follower.followPath(path);
|
||||
}
|
||||
follower.telemetryDebug(telemetryA);
|
||||
}
|
||||
}
|
@ -27,10 +27,13 @@
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package org.firstinspires.ftc.teamcode.cometbots.projects;
|
||||
package org.firstinspires.ftc.teamcode;
|
||||
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
import static org.firstinspires.ftc.teamcode.PedroConstants.BACK_ENCODER;
|
||||
import static org.firstinspires.ftc.teamcode.PedroConstants.BACK_ENCODER_DIRECTION;
|
||||
>>>>>>> branch-rc-chassis-14493
|
||||
import static org.firstinspires.ftc.teamcode.PedroConstants.BACK_LEFT_MOTOR;
|
||||
import static org.firstinspires.ftc.teamcode.PedroConstants.BACK_LEFT_MOTOR_DIRECTION;
|
||||
import static org.firstinspires.ftc.teamcode.PedroConstants.BACK_RIGHT_MOTOR;
|
||||
@ -39,19 +42,28 @@ import static org.firstinspires.ftc.teamcode.PedroConstants.FRONT_LEFT_MOTOR;
|
||||
import static org.firstinspires.ftc.teamcode.PedroConstants.FRONT_LEFT_MOTOR_DIRECTION;
|
||||
import static org.firstinspires.ftc.teamcode.PedroConstants.FRONT_RIGHT_MOTOR;
|
||||
import static org.firstinspires.ftc.teamcode.PedroConstants.FRONT_RIGHT_MOTOR_DIRECTION;
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
import static org.firstinspires.ftc.teamcode.PedroConstants.LEFT_ENCODER;
|
||||
import static org.firstinspires.ftc.teamcode.PedroConstants.LEFT_ENCODER_DIRECTION;
|
||||
import static org.firstinspires.ftc.teamcode.PedroConstants.RIGHT_ENCODER;
|
||||
import static org.firstinspires.ftc.teamcode.PedroConstants.RIGHT_ENCODER_DIRECTION;
|
||||
>>>>>>> branch-rc-chassis-14493
|
||||
|
||||
import com.qualcomm.robotcore.eventloop.opmode.Disabled;
|
||||
import com.qualcomm.robotcore.eventloop.opmode.LinearOpMode;
|
||||
import com.qualcomm.robotcore.eventloop.opmode.TeleOp;
|
||||
import com.qualcomm.robotcore.hardware.DcMotor;
|
||||
<<<<<<< HEAD
|
||||
import com.qualcomm.robotcore.util.ElapsedTime;
|
||||
|
||||
=======
|
||||
import com.qualcomm.robotcore.hardware.DcMotorEx;
|
||||
import com.qualcomm.robotcore.util.ElapsedTime;
|
||||
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.localization.Encoder;
|
||||
|
||||
>>>>>>> branch-rc-chassis-14493
|
||||
/*
|
||||
* This file contains an example of a Linear "OpMode".
|
||||
* An OpMode is a 'program' that runs in either the autonomous or the teleop period of an FTC match.
|
||||
@ -84,13 +96,27 @@ import org.firstinspires.ftc.teamcode.pedroPathing.localization.Encoder;
|
||||
public class BasicOmniOpMode_Linear extends LinearOpMode {
|
||||
|
||||
// Declare OpMode members for each of the 4 motors.
|
||||
<<<<<<< HEAD
|
||||
private ElapsedTime runtime = new ElapsedTime();
|
||||
private DcMotor leftFrontDrive = null;
|
||||
private DcMotor leftBackDrive = null;
|
||||
private DcMotor rightFrontDrive = null;
|
||||
private DcMotor rightBackDrive = null;
|
||||
=======
|
||||
private final ElapsedTime runtime = new ElapsedTime();
|
||||
>>>>>>> branch-rc-chassis-14493
|
||||
|
||||
@Override
|
||||
public void runOpMode() {
|
||||
|
||||
// Initialize the hardware variables. Note that the strings used here must correspond
|
||||
// to the names assigned during the robot configuration step on the DS or RC devices.
|
||||
<<<<<<< HEAD
|
||||
leftFrontDrive = hardwareMap.get(DcMotor.class, FRONT_LEFT_MOTOR);
|
||||
leftBackDrive = hardwareMap.get(DcMotor.class, BACK_LEFT_MOTOR);
|
||||
rightFrontDrive = hardwareMap.get(DcMotor.class, FRONT_RIGHT_MOTOR);
|
||||
rightBackDrive = hardwareMap.get(DcMotor.class, BACK_RIGHT_MOTOR);
|
||||
=======
|
||||
DcMotor leftFrontDrive = hardwareMap.get(DcMotor.class, FRONT_LEFT_MOTOR);
|
||||
DcMotor leftBackDrive = hardwareMap.get(DcMotor.class, BACK_LEFT_MOTOR);
|
||||
DcMotor rightFrontDrive = hardwareMap.get(DcMotor.class, FRONT_RIGHT_MOTOR);
|
||||
@ -107,6 +133,7 @@ public class BasicOmniOpMode_Linear extends LinearOpMode {
|
||||
leftEncoder.setDirection(LEFT_ENCODER_DIRECTION);
|
||||
rightEncoder.setDirection(RIGHT_ENCODER_DIRECTION);
|
||||
strafeEncoder.setDirection(BACK_ENCODER_DIRECTION);
|
||||
>>>>>>> branch-rc-chassis-14493
|
||||
|
||||
// ########################################################################################
|
||||
// !!! IMPORTANT Drive Information. Test your motor directions. !!!!!
|
||||
@ -125,9 +152,12 @@ public class BasicOmniOpMode_Linear extends LinearOpMode {
|
||||
|
||||
// Wait for the game to start (driver presses START)
|
||||
telemetry.addData("Status", "Initialized");
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
telemetry.addData("Left Encoder Value", leftEncoder.getDeltaPosition());
|
||||
telemetry.addData("Right Encoder Value", rightEncoder.getDeltaPosition());
|
||||
telemetry.addData("Strafe Encoder Value", strafeEncoder.getDeltaPosition());
|
||||
>>>>>>> branch-rc-chassis-14493
|
||||
telemetry.update();
|
||||
|
||||
waitForStart();
|
||||
@ -189,9 +219,12 @@ public class BasicOmniOpMode_Linear extends LinearOpMode {
|
||||
telemetry.addData("Status", "Run Time: " + runtime.toString());
|
||||
telemetry.addData("Front left/Right", "%4.2f, %4.2f", leftFrontPower, rightFrontPower);
|
||||
telemetry.addData("Back left/Right", "%4.2f, %4.2f", leftBackPower, rightBackPower);
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
telemetry.addData("Left Encoder Value", leftEncoder.getDeltaPosition());
|
||||
telemetry.addData("Right Encoder Value", rightEncoder.getDeltaPosition());
|
||||
telemetry.addData("Strafe Encoder Value", strafeEncoder.getDeltaPosition());
|
||||
>>>>>>> branch-rc-chassis-14493
|
||||
telemetry.update();
|
||||
}
|
||||
}}
|
@ -1,115 +0,0 @@
|
||||
package org.firstinspires.ftc.teamcode;
|
||||
/*
|
||||
import com.acmerobotics.dashboard.FtcDashboard;
|
||||
import com.acmerobotics.dashboard.telemetry.MultipleTelemetry;
|
||||
import com.acmerobotics.roadrunner.SleepAction;
|
||||
import com.qualcomm.robotcore.eventloop.opmode.Autonomous;
|
||||
import com.qualcomm.robotcore.eventloop.opmode.Disabled;
|
||||
import com.qualcomm.robotcore.eventloop.opmode.OpMode;
|
||||
import com.qualcomm.robotcore.util.ElapsedTime;
|
||||
|
||||
import org.firstinspires.ftc.robotcore.external.Telemetry;
|
||||
import org.firstinspires.ftc.teamcode.cometbots.CometBotTeleopCompetition;
|
||||
import org.firstinspires.ftc.teamcode.configs.RobotConstants;
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.follower.Follower;
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.localization.Pose;
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.pathGeneration.BezierCurve;
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.pathGeneration.BezierLine;
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.pathGeneration.PathBuilder;
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.pathGeneration.PathChain;
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.pathGeneration.Point;
|
||||
import org.firstinspires.ftc.teamcode.subsystem.AutoPark;
|
||||
import org.firstinspires.ftc.teamcode.subsystem.HighBasketAutoPath1;
|
||||
import org.firstinspires.ftc.teamcode.subsystem.HighBasketAutoPath2;
|
||||
import org.firstinspires.ftc.teamcode.subsystem.LiftActionsSubsystem;
|
||||
import org.firstinspires.ftc.teamcode.subsystem.SkyHookSubsystem;
|
||||
|
||||
@Autonomous(name = "Auto Test Competition", group = "Dev")
|
||||
public class BlueBasketAuto extends OpMode {
|
||||
private Follower follower;
|
||||
private int state;
|
||||
|
||||
private HighBasketAutoPath1 path1;
|
||||
private HighBasketAutoPath2 path2;
|
||||
private AutoPark pathPark;
|
||||
private SkyHookSubsystem hook;
|
||||
private CometBotTeleopCompetition comp;
|
||||
private ElapsedTime runtime;
|
||||
|
||||
private LiftActionsSubsystem liftActionsSubsystem;
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
follower = new Follower(hardwareMap);
|
||||
follower.setMaxPower(.75);
|
||||
path1 = new HighBasketAutoPath1();
|
||||
path2 = new HighBasketAutoPath2();
|
||||
pathPark = new AutoPark();
|
||||
|
||||
comp = new CometBotTeleopCompetition(hardwareMap, telemetry, gamepad1, gamepad2);
|
||||
comp.initCloseClaw();
|
||||
runtime = new ElapsedTime();
|
||||
hook = new SkyHookSubsystem(hardwareMap);
|
||||
state = 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void loop() {
|
||||
switch(state) {
|
||||
case 0:
|
||||
telemetry.addData("case0", "case0");
|
||||
|
||||
path1.moveToPath1(follower);
|
||||
state = 1;
|
||||
runtime.reset();
|
||||
case 1:
|
||||
if (runtime.seconds() > 5) {
|
||||
telemetry.addData("case1", "case1");
|
||||
|
||||
new SleepAction(.5);
|
||||
comp.highBucketDropAuto();
|
||||
|
||||
state = 2;
|
||||
}
|
||||
case 2:
|
||||
if (runtime.seconds() > 15) {
|
||||
telemetry.addData("case2", "case2");
|
||||
|
||||
// new SleepAsction(.5);
|
||||
//path2.moveToPath1(follower);
|
||||
|
||||
//For next time, add encoder control to skyhook and extend here
|
||||
//comp.moveSkyHook();
|
||||
|
||||
//pathPark.moveToPark(follower);
|
||||
|
||||
state = 3;
|
||||
}
|
||||
case 3:
|
||||
if (runtime.seconds() > 15) {
|
||||
telemetry.addData("case3", "case3");
|
||||
hook.toLevel1Position();
|
||||
|
||||
|
||||
state = 4;
|
||||
}
|
||||
case 4:
|
||||
if (runtime.seconds() > 15) {
|
||||
telemetry.addData("case3", "case3");
|
||||
hook.toLevel1Position();
|
||||
|
||||
|
||||
state = 4;
|
||||
}
|
||||
//System.out.println("default");
|
||||
//telemetry.addData("default", "default");
|
||||
//telemetry.update();
|
||||
}
|
||||
telemetry.update();
|
||||
follower.update();
|
||||
//follower.telemetryDebug(telemetry);
|
||||
}
|
||||
}
|
||||
*/
|
@ -1,24 +0,0 @@
|
||||
package org.firstinspires.ftc.teamcode;
|
||||
|
||||
import com.qualcomm.robotcore.eventloop.opmode.OpMode;
|
||||
import com.qualcomm.robotcore.eventloop.opmode.TeleOp;
|
||||
|
||||
import org.firstinspires.ftc.teamcode.cometbots.CometBotAutoDevelopment;
|
||||
|
||||
@TeleOp(name = "CometBot Auto v2", group = "Development")
|
||||
public class CometBotDevAuto extends OpMode {
|
||||
|
||||
public CometBotAutoDevelopment runMode;
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
runMode = new CometBotAutoDevelopment(hardwareMap, gamepad1, gamepad2);
|
||||
runMode.init();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loop() {
|
||||
runMode.update();
|
||||
telemetry.update();
|
||||
}
|
||||
}
|
@ -10,12 +10,14 @@ public class PedroConstants {
|
||||
/*
|
||||
Robot parameters
|
||||
*/
|
||||
// Turn localizer - -0.003
|
||||
|
||||
|
||||
// Robot motor configurations
|
||||
public static final String FRONT_LEFT_MOTOR = "front-left";
|
||||
public static final String BACK_LEFT_MOTOR = "back-left";
|
||||
public static final String FRONT_RIGHT_MOTOR = "front-right";
|
||||
public static final String BACK_RIGHT_MOTOR = "back-right";
|
||||
public static final String FRONT_LEFT_MOTOR = "Drive front lt";
|
||||
public static final String BACK_LEFT_MOTOR = "Drive back lt";
|
||||
public static final String FRONT_RIGHT_MOTOR = "Drive front rt";
|
||||
public static final String BACK_RIGHT_MOTOR = "Drive back rt";
|
||||
|
||||
// Robot motor direction
|
||||
public static final Direction FRONT_LEFT_MOTOR_DIRECTION = Direction.REVERSE;
|
||||
@ -23,64 +25,49 @@ public class PedroConstants {
|
||||
public static final Direction FRONT_RIGHT_MOTOR_DIRECTION = Direction.FORWARD;
|
||||
public static final Direction BACK_RIGHT_MOTOR_DIRECTION = Direction.FORWARD;
|
||||
|
||||
/*
|
||||
Motor Max Power
|
||||
*/
|
||||
public static final double MAX_POWER = .75;
|
||||
|
||||
// Robot IMU configuration
|
||||
public static final String IMU = "imu";
|
||||
|
||||
// Robot IMU placement
|
||||
public static final RevHubOrientationOnRobot.LogoFacingDirection IMU_LOGO_FACING_DIRECTION
|
||||
= RevHubOrientationOnRobot.LogoFacingDirection.LEFT;
|
||||
= RevHubOrientationOnRobot.LogoFacingDirection.DOWN;
|
||||
public static final RevHubOrientationOnRobot.UsbFacingDirection IMU_USB_FACING_DIRECTION
|
||||
= RevHubOrientationOnRobot.UsbFacingDirection.UP;
|
||||
= RevHubOrientationOnRobot.UsbFacingDirection.LEFT;
|
||||
|
||||
// Robot encoders
|
||||
// NOTE: Encoders are plugged into the same ports as motors hence the weird names
|
||||
public static final String RIGHT_ENCODER = "front-left"; //2
|
||||
public static final String BACK_ENCODER = "front-right"; //1
|
||||
public static final String LEFT_ENCODER = "back-right"; //0
|
||||
public static final String LEFT_ENCODER = "encoder left";
|
||||
public static final String RIGHT_ENCODER = "encoder right";
|
||||
public static final String BACK_ENCODER = "encoder back";
|
||||
|
||||
// Robot encoder direction
|
||||
public static final double LEFT_ENCODER_DIRECTION = Encoder.FORWARD;
|
||||
public static final double RIGHT_ENCODER_DIRECTION = Encoder.REVERSE;
|
||||
public static final double BACK_ENCODER_DIRECTION = Encoder.REVERSE;
|
||||
|
||||
// Arm config
|
||||
public static final String LIFT_SLIDE_LEFT_MOTOR = "lift-slide-left";
|
||||
public static final String LIFT_SLIDE_RIGHT_MOTOR = "lift-slide-right";
|
||||
public static final String CLAW_NAME = "claw-servo";
|
||||
public static final String WRIST_SERVO = "wrist-servo";
|
||||
public static final String ARM_SERVO = "arm-servo";
|
||||
public static final String THUMB_SERVO = "thumb-servo";
|
||||
public static final String HOOK = "skyhook";
|
||||
public static final double LEFT_ENCODER_DIRECTION = Encoder.REVERSE;
|
||||
public static final double RIGHT_ENCODER_DIRECTION = Encoder.FORWARD;
|
||||
public static final double BACK_ENCODER_DIRECTION = Encoder.FORWARD;
|
||||
|
||||
/*
|
||||
Pedro's parameters
|
||||
*/
|
||||
// -0.0708
|
||||
|
||||
// The weight of the robot in Kilograms
|
||||
public static final double ROBOT_WEIGHT_IN_KG = 9;
|
||||
public static final double ROBOT_WEIGHT_IN_KG = 10.5;
|
||||
|
||||
// Maximum velocity of the robot going forward
|
||||
public static final double ROBOT_SPEED_FORWARD = 50.02;
|
||||
public static final double ROBOT_SPEED_FORWARD = 51.4598;
|
||||
|
||||
// Maximum velocity of the robot going right
|
||||
public static final double ROBOT_SPEED_LATERAL = 36.07;
|
||||
public static final double ROBOT_SPEED_LATERAL = 28.7119;
|
||||
|
||||
// Rate of deceleration when power is cut-off when the robot is moving forward
|
||||
public static final double FORWARD_ZERO_POWER_ACCEL = -91.4557;
|
||||
public static final double FORWARD_ZERO_POWER_ACCEL = -57.805;
|
||||
|
||||
// Rate of deceleration when power is cut-off when the robot is moving to the right
|
||||
public static final double LATERAL_ZERO_POWER_ACCEL = -98.514;
|
||||
public static final double LATERAL_ZERO_POWER_ACCEL = -99.672;
|
||||
|
||||
// Determines how fast your robot will decelerate as a factor of how fast your robot will coast to a stop
|
||||
public static final double ZERO_POWER_ACCEL_MULT = 4.0;
|
||||
public static final double ZERO_POWER_ACCEL_MULT = 3.5;
|
||||
|
||||
/* Centripetal force correction - increase if robot is correcting into the path
|
||||
- decrease if robot is correcting away from the path */
|
||||
public static final double CENTRIPETAL_SCALING = 0.0004;
|
||||
}
|
||||
|
||||
|
@ -1,54 +0,0 @@
|
||||
package org.firstinspires.ftc.teamcode;
|
||||
|
||||
import com.acmerobotics.dashboard.FtcDashboard;
|
||||
import com.acmerobotics.dashboard.telemetry.MultipleTelemetry;
|
||||
import com.qualcomm.robotcore.eventloop.opmode.Autonomous;
|
||||
import com.qualcomm.robotcore.eventloop.opmode.OpMode;
|
||||
|
||||
import org.firstinspires.ftc.robotcore.external.Telemetry;
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.follower.Follower;
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.localization.Pose;
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.pathGeneration.BezierCurve;
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.pathGeneration.BezierLine;
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.pathGeneration.PathChain;
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.pathGeneration.Point;
|
||||
|
||||
@Autonomous(name = "Specimen Test", group = "Competition")
|
||||
public class PreLoadedBlueBasketAuto extends OpMode {
|
||||
private Telemetry telemetryA;
|
||||
|
||||
private Follower follower;
|
||||
|
||||
private PathChain path;
|
||||
|
||||
private final Pose startPose = new Pose(8, 55);
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
follower = new Follower(hardwareMap);
|
||||
|
||||
follower.setMaxPower(.45);
|
||||
|
||||
follower.setStartingPose(startPose);
|
||||
|
||||
path = follower.pathBuilder()
|
||||
.addPath(
|
||||
// Line 1
|
||||
new BezierLine(
|
||||
new Point(8, 55, Point.CARTESIAN),
|
||||
new Point(24, 21, Point.CARTESIAN)
|
||||
)
|
||||
)
|
||||
.setLinearHeadingInterpolation(Math.toRadians(0), Math.toRadians(-180)).build();
|
||||
follower.followPath(path);
|
||||
|
||||
telemetryA = new MultipleTelemetry(this.telemetry, FtcDashboard.getInstance().getTelemetry());
|
||||
telemetryA.update();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loop() {
|
||||
follower.update();
|
||||
follower.telemetryDebug(telemetryA);
|
||||
}
|
||||
}
|
@ -0,0 +1,171 @@
|
||||
/* Copyright (c) 2022 FIRST. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted (subject to the limitations in the disclaimer below) 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 nor the names of its contributors may be used to endorse or
|
||||
* promote products derived from this software without specific prior written permission.
|
||||
*
|
||||
* NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS
|
||||
* LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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.
|
||||
*/
|
||||
|
||||
package org.firstinspires.ftc.teamcode;
|
||||
|
||||
import static org.firstinspires.ftc.teamcode.PedroConstants.BACK_ENCODER;
|
||||
import static org.firstinspires.ftc.teamcode.PedroConstants.BACK_ENCODER_DIRECTION;
|
||||
import static org.firstinspires.ftc.teamcode.PedroConstants.IMU_LOGO_FACING_DIRECTION;
|
||||
import static org.firstinspires.ftc.teamcode.PedroConstants.IMU_USB_FACING_DIRECTION;
|
||||
import static org.firstinspires.ftc.teamcode.PedroConstants.LEFT_ENCODER;
|
||||
import static org.firstinspires.ftc.teamcode.PedroConstants.LEFT_ENCODER_DIRECTION;
|
||||
import static org.firstinspires.ftc.teamcode.PedroConstants.RIGHT_ENCODER;
|
||||
import static org.firstinspires.ftc.teamcode.PedroConstants.RIGHT_ENCODER_DIRECTION;
|
||||
|
||||
import com.qualcomm.hardware.rev.RevHubOrientationOnRobot;
|
||||
import com.qualcomm.robotcore.eventloop.opmode.Disabled;
|
||||
import com.qualcomm.robotcore.eventloop.opmode.LinearOpMode;
|
||||
import com.qualcomm.robotcore.eventloop.opmode.TeleOp;
|
||||
import com.qualcomm.robotcore.hardware.DcMotorEx;
|
||||
import com.qualcomm.robotcore.hardware.IMU;
|
||||
|
||||
import org.firstinspires.ftc.robotcore.external.navigation.AngleUnit;
|
||||
import org.firstinspires.ftc.robotcore.external.navigation.AngularVelocity;
|
||||
import org.firstinspires.ftc.robotcore.external.navigation.YawPitchRollAngles;
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.localization.Encoder;
|
||||
|
||||
/*
|
||||
* This OpMode shows how to use the new universal IMU interface. This
|
||||
* interface may be used with the BNO055 IMU or the BHI260 IMU. It assumes that an IMU is configured
|
||||
* on the robot with the name "imu".
|
||||
*
|
||||
* The sample will display the current Yaw, Pitch and Roll of the robot.<br>
|
||||
* With the correct orientation parameters selected, pitch/roll/yaw should act as follows:
|
||||
* Pitch value should INCREASE as the robot is tipped UP at the front. (Rotation about X) <br>
|
||||
* Roll value should INCREASE as the robot is tipped UP at the left side. (Rotation about Y) <br>
|
||||
* Yaw value should INCREASE as the robot is rotated Counter Clockwise. (Rotation about Z) <br>
|
||||
*
|
||||
* The yaw can be reset (to zero) by pressing the Y button on the gamepad (Triangle on a PS4 controller)
|
||||
*
|
||||
* This specific sample assumes that the Hub is mounted on one of the three orthogonal planes
|
||||
* (X/Y, X/Z or Y/Z) and that the Hub has only been rotated in a range of 90 degree increments.
|
||||
*
|
||||
* Note: if your Hub is mounted on a surface angled at some non-90 Degree multiple (like 30) look at
|
||||
* the alternative SensorIMUNonOrthogonal sample in this folder.
|
||||
*
|
||||
* This "Orthogonal" requirement means that:
|
||||
*
|
||||
* 1) The Logo printed on the top of the Hub can ONLY be pointing in one of six directions:
|
||||
* FORWARD, BACKWARD, UP, DOWN, LEFT and RIGHT.
|
||||
*
|
||||
* 2) The USB ports can only be pointing in one of the same six directions:<br>
|
||||
* FORWARD, BACKWARD, UP, DOWN, LEFT and RIGHT.
|
||||
*
|
||||
* So, To fully define how your Hub is mounted to the robot, you must simply specify:<br>
|
||||
* logoFacingDirection<br>
|
||||
* usbFacingDirection
|
||||
*
|
||||
* Use Android Studio to Copy this Class, and Paste it into your team's code folder with a new name.
|
||||
* Remove or comment out the @Disabled line to add this OpMode to the Driver Station OpMode list.
|
||||
*
|
||||
* Finally, choose the two correct parameters to define how your Hub is mounted and edit this OpMode
|
||||
* to use those parameters.
|
||||
*/
|
||||
@TeleOp(name = "Sensor: IMU Orthogonal", group = "Sensor")
|
||||
@Disabled // Comment this out to add to the OpMode list
|
||||
public class SensorIMUOrthogonal extends LinearOpMode {
|
||||
// The IMU sensor object
|
||||
IMU imu;
|
||||
private Encoder leftEncoder;
|
||||
private Encoder rightEncoder;
|
||||
private Encoder strafeEncoder;
|
||||
|
||||
//----------------------------------------------------------------------------------------------
|
||||
// Main logic
|
||||
//----------------------------------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public void runOpMode() throws InterruptedException {
|
||||
|
||||
// Retrieve and initialize the IMU.
|
||||
// This sample expects the IMU to be in a REV Hub and named "imu".
|
||||
imu = hardwareMap.get(IMU.class, PedroConstants.IMU);
|
||||
|
||||
// TODO: replace these with your encoder ports
|
||||
leftEncoder = new Encoder(hardwareMap.get(DcMotorEx.class, LEFT_ENCODER));
|
||||
rightEncoder = new Encoder(hardwareMap.get(DcMotorEx.class, RIGHT_ENCODER));
|
||||
strafeEncoder = new Encoder(hardwareMap.get(DcMotorEx.class, BACK_ENCODER));
|
||||
|
||||
// TODO: reverse any encoders necessary
|
||||
leftEncoder.setDirection(LEFT_ENCODER_DIRECTION);
|
||||
rightEncoder.setDirection(RIGHT_ENCODER_DIRECTION);
|
||||
strafeEncoder.setDirection(BACK_ENCODER_DIRECTION);
|
||||
|
||||
/* Define how the hub is mounted on the robot to get the correct Yaw, Pitch and Roll values.
|
||||
*
|
||||
* Two input parameters are required to fully specify the Orientation.
|
||||
* The first parameter specifies the direction the printed logo on the Hub is pointing.
|
||||
* The second parameter specifies the direction the USB connector on the Hub is pointing.
|
||||
* All directions are relative to the robot, and left/right is as-viewed from behind the robot.
|
||||
*
|
||||
* If you are using a REV 9-Axis IMU, you can use the Rev9AxisImuOrientationOnRobot class instead of the
|
||||
* RevHubOrientationOnRobot class, which has an I2cPortFacingDirection instead of a UsbFacingDirection.
|
||||
*/
|
||||
|
||||
/* The next two lines define Hub orientation.
|
||||
* The Default Orientation (shown) is when a hub is mounted horizontally with the printed logo pointing UP and the USB port pointing FORWARD.
|
||||
*
|
||||
* To Do: EDIT these two lines to match YOUR mounting configuration.
|
||||
*/
|
||||
RevHubOrientationOnRobot.LogoFacingDirection logoDirection = IMU_LOGO_FACING_DIRECTION;
|
||||
RevHubOrientationOnRobot.UsbFacingDirection usbDirection = IMU_USB_FACING_DIRECTION;
|
||||
|
||||
RevHubOrientationOnRobot orientationOnRobot = new RevHubOrientationOnRobot(logoDirection, usbDirection);
|
||||
|
||||
// Now initialize the IMU with this mounting orientation
|
||||
// Note: if you choose two conflicting directions, this initialization will cause a code exception.
|
||||
imu.initialize(new IMU.Parameters(orientationOnRobot));
|
||||
|
||||
// Loop and update the dashboard
|
||||
while (!isStopRequested()) {
|
||||
|
||||
telemetry.addData("Hub orientation", "Logo=%s USB=%s\n ", logoDirection, usbDirection);
|
||||
|
||||
// Check to see if heading reset is requested
|
||||
if (gamepad1.y) {
|
||||
telemetry.addData("Yaw", "Resetting\n");
|
||||
imu.resetYaw();
|
||||
} else {
|
||||
telemetry.addData("Yaw", "Press Y (triangle) on Gamepad to reset\n");
|
||||
}
|
||||
|
||||
// Retrieve Rotational Angles and Velocities
|
||||
YawPitchRollAngles orientation = imu.getRobotYawPitchRollAngles();
|
||||
AngularVelocity angularVelocity = imu.getRobotAngularVelocity(AngleUnit.DEGREES);
|
||||
|
||||
telemetry.addData("Yaw (Z)", "%.2f Deg. (Heading)", orientation.getYaw(AngleUnit.DEGREES));
|
||||
telemetry.addData("Pitch (X)", "%.2f Deg.", orientation.getPitch(AngleUnit.DEGREES));
|
||||
telemetry.addData("Roll (Y)", "%.2f Deg.\n", orientation.getRoll(AngleUnit.DEGREES));
|
||||
telemetry.addData("Yaw (Z) velocity", "%.2f Deg/Sec", angularVelocity.zRotationRate);
|
||||
telemetry.addData("Pitch (X) velocity", "%.2f Deg/Sec", angularVelocity.xRotationRate);
|
||||
telemetry.addData("Roll (Y) velocity", "%.2f Deg/Sec", angularVelocity.yRotationRate);
|
||||
telemetry.update();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,165 @@
|
||||
package org.firstinspires.ftc.teamcode;
|
||||
|
||||
import com.qualcomm.robotcore.eventloop.opmode.OpMode;
|
||||
import com.qualcomm.robotcore.eventloop.opmode.TeleOp;
|
||||
import com.qualcomm.robotcore.hardware.DcMotor;
|
||||
import com.qualcomm.robotcore.hardware.Servo;
|
||||
import com.qualcomm.robotcore.util.ElapsedTime;
|
||||
|
||||
import org.firstinspires.ftc.robotcontroller.external.samples.UtilityOctoQuadConfigMenu;
|
||||
import org.firstinspires.ftc.robotcore.external.Telemetry;
|
||||
|
||||
|
||||
@TeleOp(name = "ArmControl")
|
||||
public class SlideArm extends OpMode {
|
||||
|
||||
|
||||
|
||||
DcMotor Slide;
|
||||
Servo ClawServo;
|
||||
Servo ArmServo;
|
||||
Servo WristServo;
|
||||
boolean xPressed;
|
||||
boolean yPressed;
|
||||
boolean bPressed;
|
||||
double ticks = 753.2;
|
||||
|
||||
|
||||
public void init(){
|
||||
Slide = hardwareMap.get(DcMotor.class, "SlideMotor");
|
||||
ArmServo = hardwareMap.get(Servo.class,"WristServo");
|
||||
WristServo = hardwareMap.get(Servo.class, "ArmServo");
|
||||
ClawServo = hardwareMap.get(Servo.class, "ClawServo");
|
||||
xPressed = false;
|
||||
yPressed = false;
|
||||
bPressed = false;
|
||||
}
|
||||
|
||||
double power = 0;
|
||||
double position = 1;
|
||||
|
||||
public void loop() {
|
||||
Slide.setPower(-gamepad2.left_stick_y);
|
||||
Slide.setZeroPowerBehavior(DcMotor.ZeroPowerBehavior.BRAKE);
|
||||
if (gamepad2.left_bumper) {
|
||||
ClawServo.setPosition(0);
|
||||
} else if (gamepad2.right_bumper) {
|
||||
ClawServo.setPosition(1);
|
||||
}
|
||||
|
||||
/*if(gamepad2.dpad_down){
|
||||
WristServo.setPosition(0.78);
|
||||
ArmServo.setPosition(0.55);
|
||||
}
|
||||
else if (gamepad2.dpad_up){
|
||||
WristServo.setPosition(0.4);
|
||||
ArmServo.setPosition(0.2);
|
||||
|
||||
}*/
|
||||
if (gamepad2.a) {
|
||||
Slide.setMode(DcMotor.RunMode.STOP_AND_RESET_ENCODER);
|
||||
}
|
||||
|
||||
if (gamepad2.dpad_down) {
|
||||
SlideArm.ServoSteps(WristServo, 0.78, 4, 8);
|
||||
try {
|
||||
Thread.sleep(50);
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
SlideArm.ServoSteps(ArmServo, 0.55, 10, 5);
|
||||
} else if (gamepad2.dpad_up) {
|
||||
|
||||
WristServo.setPosition(0.4);
|
||||
ArmServo.setPosition(0.2);
|
||||
|
||||
}
|
||||
|
||||
telemetry.addData("Slide Ticks", Slide.getCurrentPosition());
|
||||
telemetry.update();
|
||||
//limit = 6600;
|
||||
|
||||
|
||||
if (gamepad2.x) {
|
||||
xPressed = true;
|
||||
}
|
||||
|
||||
while (xPressed && Slide.getCurrentPosition() < 6300) {
|
||||
Slide.setPower(0.6);
|
||||
Slide.setTargetPosition(6300);
|
||||
Slide.setMode(DcMotor.RunMode.RUN_TO_POSITION);
|
||||
telemetry.addData("In While Loop:", Slide.getCurrentPosition());
|
||||
telemetry.update();
|
||||
}
|
||||
if (xPressed && Slide.getCurrentPosition() >= 6300)
|
||||
{
|
||||
xPressed = false;
|
||||
}
|
||||
|
||||
Slide.setPower(0);
|
||||
|
||||
if (gamepad2.y) {
|
||||
yPressed = false;
|
||||
}
|
||||
|
||||
while (yPressed && Slide.getCurrentPosition() < 3150) {
|
||||
Slide.setPower(0.6);
|
||||
Slide.setTargetPosition(3150);
|
||||
Slide.setMode(DcMotor.RunMode.RUN_TO_POSITION);
|
||||
telemetry.addData("In While Loop:", Slide.getCurrentPosition());
|
||||
telemetry.update();
|
||||
}
|
||||
Slide.setPower(0);
|
||||
if (yPressed && Slide.getCurrentPosition() >= 3150)
|
||||
{
|
||||
yPressed = false;
|
||||
}
|
||||
if (gamepad2.b) {
|
||||
bPressed = !bPressed;
|
||||
}
|
||||
|
||||
while (bPressed && Slide.getCurrentPosition() > 0) {
|
||||
Slide.setPower(0.6);
|
||||
Slide.setTargetPosition(0);
|
||||
Slide.setMode(DcMotor.RunMode.RUN_TO_POSITION);
|
||||
telemetry.addData("In While Loop:", Slide.getCurrentPosition());
|
||||
telemetry.update();
|
||||
}
|
||||
Slide.setPower(0);
|
||||
if (xPressed && Slide.getCurrentPosition() >= 0)
|
||||
{
|
||||
bPressed = false;
|
||||
} }
|
||||
|
||||
/**
|
||||
* This function takes 4 parameters and makes your servo move in multiple steps for precision
|
||||
* @param servo the servo you want to move
|
||||
* @param targetPosition the position you want to go to
|
||||
* @param Steps how many steps you want to move before reaching targetPosition
|
||||
* @param millis how much to sleep between steps
|
||||
*/
|
||||
public static void ServoSteps (Servo servo, double targetPosition, int Steps, long millis){
|
||||
double startingPosition = servo.getPosition();
|
||||
double howFarToMove = targetPosition-startingPosition;
|
||||
double Increment = howFarToMove/Steps;
|
||||
double currentPosition = startingPosition;
|
||||
for(int i = 0; i < Steps; i ++) {
|
||||
servo.setPosition(currentPosition + Increment);
|
||||
currentPosition += Increment;
|
||||
try {
|
||||
Thread.sleep(millis);
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void stop(){
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -1,207 +0,0 @@
|
||||
package org.firstinspires.ftc.teamcode.cometbots;
|
||||
|
||||
import static org.firstinspires.ftc.teamcode.PedroConstants.MAX_POWER;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.acmerobotics.dashboard.telemetry.TelemetryPacket;
|
||||
import com.acmerobotics.roadrunner.Action;
|
||||
import com.acmerobotics.roadrunner.SequentialAction;
|
||||
import com.acmerobotics.roadrunner.SleepAction;
|
||||
import com.acmerobotics.roadrunner.ftc.Actions;
|
||||
import com.qualcomm.robotcore.hardware.Gamepad;
|
||||
import com.qualcomm.robotcore.hardware.HardwareMap;
|
||||
|
||||
import org.firstinspires.ftc.robotcore.external.Telemetry;
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.follower.Follower;
|
||||
import org.firstinspires.ftc.teamcode.states.FieldStates;
|
||||
import org.firstinspires.ftc.teamcode.subsystem.ArmSubsystem;
|
||||
import org.firstinspires.ftc.teamcode.subsystem.ClawSubsystem;
|
||||
import org.firstinspires.ftc.teamcode.subsystem.DualMotorSliderSubsystem;
|
||||
import org.firstinspires.ftc.teamcode.subsystem.HangMotorSubsystem;
|
||||
import org.firstinspires.ftc.teamcode.subsystem.MotorsSubsystem;
|
||||
import org.firstinspires.ftc.teamcode.subsystem.WristSubsystem;
|
||||
|
||||
public class CometBotAutoDevelopment {
|
||||
|
||||
/*
|
||||
Subsystems
|
||||
*/
|
||||
private DualMotorSliderSubsystem dualSlides;
|
||||
private ClawSubsystem claw;
|
||||
private WristSubsystem wrist;
|
||||
private ArmSubsystem arm;
|
||||
private HangMotorSubsystem hang;
|
||||
/*
|
||||
Controllers
|
||||
*/
|
||||
public Gamepad gamepad1;
|
||||
public Gamepad gamepad2;
|
||||
public Gamepad currentGamepad1;
|
||||
public Gamepad currentGamepad2;
|
||||
public Gamepad previousGamepad1;
|
||||
public Gamepad previousGamepad2;
|
||||
|
||||
|
||||
private Follower follower;
|
||||
|
||||
public CometBotAutoDevelopment(HardwareMap hardwareMap, Gamepad gamepad1, Gamepad gamepad2) {
|
||||
dualSlides = new DualMotorSliderSubsystem(hardwareMap);
|
||||
claw = new ClawSubsystem(hardwareMap);
|
||||
arm = new ArmSubsystem(hardwareMap);
|
||||
wrist = new WristSubsystem(hardwareMap);
|
||||
hang = new HangMotorSubsystem(hardwareMap);
|
||||
|
||||
this.gamepad1 = gamepad1;
|
||||
this.gamepad2 = gamepad2;
|
||||
currentGamepad1 = new Gamepad();
|
||||
currentGamepad2 = new Gamepad();
|
||||
previousGamepad1 = new Gamepad();
|
||||
previousGamepad2 = new Gamepad();
|
||||
follower = new Follower(hardwareMap);
|
||||
}
|
||||
|
||||
public void init() {
|
||||
dualSlides.init();
|
||||
claw.init();
|
||||
wrist.initTeleOp();
|
||||
arm.initTeleOp();
|
||||
follower.setMaxPower(MAX_POWER);
|
||||
follower.startTeleopDrive();
|
||||
}
|
||||
|
||||
public void update() {
|
||||
previousGamepad1.copy(currentGamepad1);
|
||||
currentGamepad1.copy(gamepad1);
|
||||
previousGamepad2.copy(currentGamepad2);
|
||||
currentGamepad2.copy(gamepad2);
|
||||
|
||||
//slides
|
||||
dualSlides.update();
|
||||
dualSlidesToLowBucketPosition();
|
||||
dualSlidesToHighBucketPosition();
|
||||
dualSlidesToFloorPosition();
|
||||
//arm
|
||||
armToParkPosition();
|
||||
armAndWristToFloor();
|
||||
armToBucketPosition();
|
||||
//claw
|
||||
openClaw();
|
||||
openThumb();
|
||||
//hang
|
||||
grabBlueberrySkyhook();
|
||||
hangSkyhook();
|
||||
robotDown();
|
||||
robotUp();
|
||||
stopHook();
|
||||
follower.setTeleOpMovementVectors(-gamepad1.left_stick_y, -gamepad1.left_stick_x, -gamepad1.right_stick_x);
|
||||
follower.update();
|
||||
}
|
||||
private void grabBlueberrySkyhook () {
|
||||
if(currentGamepad1.x){
|
||||
claw.grabBlueberry();
|
||||
wrist.grabBlueberrySkyhook();
|
||||
arm.grabBlueberrySkyhook();
|
||||
}
|
||||
if(arm.getState() == ArmSubsystem.ArmState.GRAB_BLUEBERRY_SKYHOOK)
|
||||
claw.init();
|
||||
}
|
||||
private void hangSkyhook (){
|
||||
dualSlides.toHangHeight();
|
||||
wrist.hangBlueberrySkyhook();
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
arm.hangBlueberrySkyhook();
|
||||
if(arm.getState() == ArmSubsystem.ArmState.HANG_BLUEBERRY_SKYHOOK){
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}claw.closeClaw();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void openClaw(){
|
||||
if(currentGamepad2.right_bumper && !previousGamepad2.right_bumper){
|
||||
claw.switchState();
|
||||
}
|
||||
}
|
||||
private void openThumb(){
|
||||
if(currentGamepad2.left_bumper && !previousGamepad2.left_bumper){
|
||||
claw.switchTState();
|
||||
}
|
||||
}
|
||||
private void armAndWristToFloor(){
|
||||
if(currentGamepad2.a && !previousGamepad2.a){
|
||||
|
||||
double increment = 0.7 - arm.getPosition();
|
||||
for(int i = 0; i < 3; i ++){
|
||||
arm.setPosition(arm.getPosition() + increment);
|
||||
try {
|
||||
Thread.sleep(50);
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
arm.toFloorPosition();
|
||||
}
|
||||
if(currentGamepad2.a && !previousGamepad2.a ){
|
||||
wrist.switchState();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
private void armToBucketPosition(){
|
||||
if(currentGamepad2.dpad_up && !previousGamepad2.dpad_up){
|
||||
arm.toBucketPosition();
|
||||
wrist.toBucketPosition();
|
||||
|
||||
}
|
||||
}
|
||||
private void armToParkPosition(){
|
||||
if(currentGamepad2.x && !previousGamepad2.x){
|
||||
arm.toParkPosition();
|
||||
wrist.toFloorPosition();
|
||||
}
|
||||
}
|
||||
|
||||
private void dualSlidesToHighBucketPosition() {
|
||||
if (currentGamepad2.y && !previousGamepad2.y) {
|
||||
dualSlides.toHighBucketPosition();
|
||||
}
|
||||
}
|
||||
private void robotUp(){
|
||||
if(currentGamepad1.dpad_up && !previousGamepad1.dpad_up){
|
||||
dualSlides.toHangBelowFloor();
|
||||
dualSlides.update();
|
||||
hang.hangRobot();
|
||||
}
|
||||
|
||||
}
|
||||
private void robotDown(){
|
||||
if(currentGamepad1.dpad_down && !previousGamepad1.dpad_down){
|
||||
hang.robotToFloor();
|
||||
}
|
||||
}
|
||||
private void stopHook(){
|
||||
if(gamepad1.left_bumper){
|
||||
hang.disableMotor();
|
||||
}
|
||||
}
|
||||
private void dualSlidesToFloorPosition() {
|
||||
if (currentGamepad2.dpad_down && !previousGamepad2.dpad_down) {
|
||||
dualSlides.toFloorPosition();
|
||||
}
|
||||
}
|
||||
private void dualSlidesToLowBucketPosition() {
|
||||
if (currentGamepad2.b && !previousGamepad2.b) {
|
||||
dualSlides.toLowBucketPosition();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,302 +0,0 @@
|
||||
package org.firstinspires.ftc.teamcode.cometbots.paths;
|
||||
|
||||
import static com.qualcomm.hardware.lynx.commands.core.LynxSetMotorPIDFControlLoopCoefficientsCommand.InternalMotorControlAlgorithm.Max;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.acmerobotics.dashboard.telemetry.TelemetryPacket;
|
||||
import com.acmerobotics.roadrunner.Action;
|
||||
import com.acmerobotics.roadrunner.SequentialAction;
|
||||
import com.acmerobotics.roadrunner.SleepAction;
|
||||
import com.acmerobotics.roadrunner.ftc.Actions;
|
||||
import com.qualcomm.robotcore.eventloop.opmode.Autonomous;
|
||||
import com.qualcomm.robotcore.eventloop.opmode.OpMode;
|
||||
import com.qualcomm.robotcore.util.ElapsedTime;
|
||||
|
||||
//import org.firstinspires.ftc.teamcode.cometbots.CometBotTeleopCompetition;
|
||||
//import org.firstinspires.ftc.teamcode.cometbots.paths.HighBasketPath1;
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.follower.Follower;
|
||||
//import org.firstinspires.ftc.teamcode.subsystem.AutoPark;
|
||||
import org.firstinspires.ftc.teamcode.cometbots.paths.HighBasketPath1;
|
||||
import org.firstinspires.ftc.teamcode.subsystem.ArmSubsystem;
|
||||
import org.firstinspires.ftc.teamcode.subsystem.ClawSubsystem;
|
||||
import org.firstinspires.ftc.teamcode.subsystem.DualMotorSliderSubsystem;
|
||||
import org.firstinspires.ftc.teamcode.subsystem.WristSubsystem;
|
||||
//import org.firstinspires.ftc.teamcode.subsystem.HighBasketAutoPath2;
|
||||
//import org.firstinspires.ftc.teamcode.subsystem.HighBasketAutoPath3;
|
||||
//import org.firstinspires.ftc.teamcode.subsystem.HighBasketAutoPath4;
|
||||
//import org.firstinspires.ftc.teamcode.subsystem.HighBasketAutoPath5;
|
||||
//import org.firstinspires.ftc.teamcode.subsystem.HighBasketAutoPath6;
|
||||
//import org.firstinspires.ftc.teamcode.subsystem.LiftActionsSubsystem;
|
||||
//import org.firstinspires.ftc.teamcode.subsystem.SkyHookSubsystem;
|
||||
|
||||
|
||||
@Autonomous(name = "Auto Test Competition V2", group = "Dev")
|
||||
public class CometBotDriveV2 extends OpMode {
|
||||
private Follower follower;
|
||||
private int state;
|
||||
|
||||
private HighBasketPath1 path1;
|
||||
private HighBasketPath2 path2;
|
||||
private HighBasketPath3 path3;
|
||||
|
||||
|
||||
|
||||
//private CometBotTeleopCompetition comp;
|
||||
private static ElapsedTime runtime;
|
||||
private static boolean initalized = false;
|
||||
private static boolean followingPath = false;
|
||||
private DualMotorSliderSubsystem lift;
|
||||
private ClawSubsystem claw;
|
||||
private WristSubsystem wrist;
|
||||
private ArmSubsystem arm;
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
follower = new Follower(hardwareMap);
|
||||
follower.setMaxPower(.75);
|
||||
|
||||
path1 = new HighBasketPath1();
|
||||
path2 = new HighBasketPath2();
|
||||
path3 = new HighBasketPath3();
|
||||
lift = new DualMotorSliderSubsystem(hardwareMap);
|
||||
arm = new ArmSubsystem(hardwareMap);
|
||||
wrist = new WristSubsystem(hardwareMap);
|
||||
claw = new ClawSubsystem(hardwareMap);
|
||||
|
||||
|
||||
|
||||
lift.init();
|
||||
arm.initAuto();
|
||||
wrist.InitAuto();
|
||||
claw.init();
|
||||
|
||||
//comp = new CometBotTeleopCompetition(hardwareMap, telemetry, gamepad1, gamepad2);
|
||||
// comp.initCloseClaw();
|
||||
|
||||
}
|
||||
|
||||
|
||||
public void loop() {
|
||||
telemetry.addData("state", state);
|
||||
telemetry.addData("followingPath", followingPath);
|
||||
telemetry.addData("busy", follower.isBusy());
|
||||
if (runtime != null) {
|
||||
telemetry.addData("Runtime (seconds)", runtime.seconds());
|
||||
}
|
||||
switch (state) {
|
||||
case 0:
|
||||
moveToPathOneAndHighBucket();
|
||||
break;
|
||||
case 1:
|
||||
doArmThing();
|
||||
state = 2;
|
||||
break;
|
||||
case 2:
|
||||
moveToPathTwoAndPickSampleUp();
|
||||
break;
|
||||
case 3:
|
||||
// doPickUpThing();
|
||||
state = 4;
|
||||
break;
|
||||
case 4:
|
||||
// moveToBasketPath3();
|
||||
break;
|
||||
// case 5:
|
||||
// theArmThing();
|
||||
// break;
|
||||
// case 6:
|
||||
// moveToPickupAgainPath4();
|
||||
// break;
|
||||
// case 7:
|
||||
// doPickUpThingAgain();
|
||||
// break;
|
||||
// case 8:
|
||||
// moveToPickupAgainPath5();
|
||||
// break;
|
||||
// case 9:
|
||||
// //theArmThingAgain();
|
||||
// break;
|
||||
// case 10:
|
||||
// //moveToParkPath6();
|
||||
// break;
|
||||
// case 11:
|
||||
|
||||
|
||||
}
|
||||
telemetry.update();
|
||||
|
||||
follower.update();
|
||||
|
||||
|
||||
}
|
||||
|
||||
private void moveToPathOneAndHighBucket() {
|
||||
path1.moveToPath1(follower);
|
||||
state = 1;
|
||||
}
|
||||
|
||||
public class SetStateAction implements Action {
|
||||
|
||||
private int value;
|
||||
|
||||
public SetStateAction(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
@Override
|
||||
public boolean run(@NonNull TelemetryPacket telemetryPacket) {
|
||||
state = value;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private Action setStateValue(int value) {
|
||||
return new SetStateAction(value);
|
||||
}
|
||||
|
||||
private void doArmThing() {
|
||||
|
||||
lift.toHighBucketReverseDrop();
|
||||
arm.toBucketPosition();
|
||||
wrist.toBucketPosition();
|
||||
claw.openClaw();
|
||||
wrist.toFloorPosition();
|
||||
|
||||
state = 2;
|
||||
}
|
||||
|
||||
|
||||
// private void theArmThing() {
|
||||
// telemetry.addData("busy?", follower.isBusy());
|
||||
// telemetry.addData("end?", follower.atParametricEnd());
|
||||
// if (follower.atParametricEnd()){
|
||||
// follower.breakFollowing();
|
||||
// comp.highBucketDropAuto();
|
||||
// state = 6;
|
||||
// }
|
||||
// follower.breakFollowing();
|
||||
// }
|
||||
|
||||
// private void theArmThingAgain() {
|
||||
// follower.breakFollowing();
|
||||
// comp.highBucketDropAuto();
|
||||
// state = 10;
|
||||
// }
|
||||
|
||||
private void moveToPathTwoAndPickSampleUp() {
|
||||
if (!follower.isBusy()) {
|
||||
path2.moveToPath2(follower);
|
||||
state = 3;
|
||||
}
|
||||
}
|
||||
//
|
||||
private void moveToBasketPath3() {
|
||||
if (!follower.isBusy()) {
|
||||
path3.moveToBasketPath3(follower);
|
||||
state = 5;
|
||||
}
|
||||
}
|
||||
|
||||
// private void moveToPickupAgainPath4() {
|
||||
// if (!followingPath) {
|
||||
// path4.moveToPickupAgainPath4(follower);
|
||||
// followingPath = true;
|
||||
// }
|
||||
// if (runtime != null) {
|
||||
// telemetry.addData("Runtime (seconds)", runtime.seconds());
|
||||
// if (follower.atParametricEnd() || runtime.seconds() > 27.0) {
|
||||
// state = 7;
|
||||
// followingPath = false;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private void moveToPickupAgainPath5() {
|
||||
// if (!followingPath) {
|
||||
// path5.moveToPickupAgainPath5(follower);
|
||||
// followingPath = true;
|
||||
// }
|
||||
// if (runtime != null) {
|
||||
// telemetry.addData("Runtime (seconds)", runtime.seconds());
|
||||
// if (follower.atParametricEnd() || runtime.seconds() > 36.0) {
|
||||
// state = 9;
|
||||
// followingPath = false;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// private void moveToParkPath6() {
|
||||
// if (!followingPath) {
|
||||
// path6.moveToParkPath6(follower);
|
||||
// followingPath = true;
|
||||
// }
|
||||
// if (runtime != null) {
|
||||
// telemetry.addData("Runtime (seconds)", runtime.seconds());
|
||||
// if (follower.atParametricEnd() || runtime.seconds() > 48.0) {
|
||||
// state = 11;
|
||||
// followingPath = false;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private void moveToBasketPath3() {
|
||||
// if (!followingPath) {
|
||||
// path3.moveToBasketPath3(follower);
|
||||
// followingPath = true;
|
||||
// }
|
||||
// if (runtime != null) {
|
||||
// telemetry.addData("Runtime (seconds)", runtime.seconds());
|
||||
// if (follower.atParametricEnd() || runtime.seconds() > 10.0) {
|
||||
// state = 5;
|
||||
// followingPath = false;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private void thePickUpAuto() {
|
||||
// Actions.runBlocking(new SequentialAction(
|
||||
// new SleepAction(.1),
|
||||
// comp.claw.openClaw(),
|
||||
// new SleepAction(.2),
|
||||
// comp.wrist.toPickupPosition(),
|
||||
// new SleepAction(.2),
|
||||
// comp.arm.toSubmarinePosition(),
|
||||
// new SleepAction(.5),
|
||||
// comp.claw.closeClaw(),
|
||||
// new SleepAction(.3),
|
||||
// comp.wrist.toFloorPosition(),
|
||||
// new SleepAction(.2),
|
||||
// comp.arm.toParkPosition(),
|
||||
// new SleepAction(.2)
|
||||
// ));
|
||||
// }
|
||||
// private void thePickUp() {
|
||||
// Actions.runBlocking(new SequentialAction(
|
||||
// new SleepAction(.5),
|
||||
// comp.wrist.toPickupPosition(),
|
||||
// new SleepAction(.5),
|
||||
// comp.arm.toSubmarinePosition(),
|
||||
// new SleepAction(.7),
|
||||
// comp.claw.closeClaw(),
|
||||
// new SleepAction(.7),
|
||||
// comp.wrist.toFloorPosition(),
|
||||
// new SleepAction(.5),
|
||||
// comp.arm.toParkPosition(),
|
||||
// new SleepAction(.5)
|
||||
// ));
|
||||
// }
|
||||
//
|
||||
// private void doPickUpThing() {
|
||||
// follower.breakFollowing();
|
||||
// thePickUpAuto();
|
||||
// state = 4;
|
||||
// }
|
||||
//
|
||||
// private void doPickUpThingAgain() {
|
||||
// follower.breakFollowing();
|
||||
// thePickUpAuto();
|
||||
// state = 8;
|
||||
// }
|
||||
//
|
||||
//
|
||||
}
|
||||
|
@ -1,39 +0,0 @@
|
||||
package org.firstinspires.ftc.teamcode.cometbots.paths;
|
||||
|
||||
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.follower.Follower;
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.localization.Pose;
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.pathGeneration.BezierCurve;
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.pathGeneration.BezierLine;
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.pathGeneration.PathBuilder;
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.pathGeneration.PathChain;
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.pathGeneration.Point;
|
||||
|
||||
|
||||
/*
|
||||
AutoLine# - This file does something of a path......
|
||||
|
||||
*/
|
||||
public class HighBasketPath1 {
|
||||
|
||||
private final Pose startPose = new Pose(10, 89);
|
||||
|
||||
public void moveToPath1(Follower robot) {
|
||||
PathChain pathChain;
|
||||
robot.setStartingPose(startPose);
|
||||
PathBuilder builder = new PathBuilder();
|
||||
builder
|
||||
.addPath(
|
||||
// Line 1
|
||||
new BezierLine(
|
||||
new Point(10.000, 89.000, Point.CARTESIAN),
|
||||
new Point(20.000, 130.000, Point.CARTESIAN)
|
||||
)
|
||||
)
|
||||
.setLinearHeadingInterpolation(Math.toRadians(0), Math.toRadians(320));
|
||||
pathChain = builder.build();
|
||||
robot.followPath(pathChain);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,36 +0,0 @@
|
||||
package org.firstinspires.ftc.teamcode.cometbots.paths;
|
||||
|
||||
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.follower.Follower;
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.localization.Pose;
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.pathGeneration.BezierLine;
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.pathGeneration.PathBuilder;
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.pathGeneration.PathChain;
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.pathGeneration.Point;
|
||||
|
||||
|
||||
/*
|
||||
AutoLine# - This file does something of a path......
|
||||
|
||||
*/
|
||||
public class HighBasketPath2 {
|
||||
|
||||
|
||||
public void moveToPath2(Follower robot) {
|
||||
PathChain pathChain;
|
||||
PathBuilder builder = new PathBuilder();
|
||||
builder
|
||||
.addPath(
|
||||
// Line 1
|
||||
new BezierLine(
|
||||
new Point(20.000, 130.000, Point.CARTESIAN),
|
||||
new Point(26.000, 117.000, Point.CARTESIAN)
|
||||
)
|
||||
)
|
||||
.setLinearHeadingInterpolation(Math.toRadians(0), Math.toRadians(0));
|
||||
pathChain = builder.build();
|
||||
robot.followPath(pathChain);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,35 +0,0 @@
|
||||
package org.firstinspires.ftc.teamcode.cometbots.paths;
|
||||
|
||||
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.follower.Follower;
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.pathGeneration.BezierLine;
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.pathGeneration.PathBuilder;
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.pathGeneration.PathChain;
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.pathGeneration.Point;
|
||||
|
||||
|
||||
/*
|
||||
AutoLine# - This file does something of a path......
|
||||
|
||||
*/
|
||||
public class HighBasketPath3 {
|
||||
|
||||
|
||||
public void moveToBasketPath3(Follower robot) {
|
||||
PathChain pathChain;
|
||||
PathBuilder builder = new PathBuilder();
|
||||
builder
|
||||
.addPath(
|
||||
// Line 1
|
||||
new BezierLine(
|
||||
new Point(26.000, 117.000, Point.CARTESIAN),
|
||||
new Point(10.000, 89.00, Point.CARTESIAN)
|
||||
)
|
||||
)
|
||||
.setLinearHeadingInterpolation(Math.toRadians(0), Math.toRadians(320));
|
||||
pathChain = builder.build();
|
||||
robot.followPath(pathChain);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,95 +0,0 @@
|
||||
/* Copyright (c) 2021 FIRST. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted (subject to the limitations in the disclaimer below) 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 nor the names of its contributors may be used to endorse or
|
||||
* promote products derived from this software without specific prior written permission.
|
||||
*
|
||||
* NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS
|
||||
* LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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.
|
||||
*/
|
||||
|
||||
package org.firstinspires.ftc.teamcode.cometbots.tests;
|
||||
|
||||
import com.qualcomm.robotcore.eventloop.opmode.LinearOpMode;
|
||||
import com.qualcomm.robotcore.eventloop.opmode.TeleOp;
|
||||
import com.qualcomm.robotcore.hardware.Gamepad;
|
||||
import com.qualcomm.robotcore.util.ElapsedTime;
|
||||
|
||||
import org.firstinspires.ftc.teamcode.subsystem.ArmSubsystem;
|
||||
|
||||
@TeleOp(name = "Arm Test v2", group = "Debug")
|
||||
public class ArmTest extends LinearOpMode {
|
||||
|
||||
// Declare OpMode members for each of the 4 motors.
|
||||
private final ElapsedTime runtime = new ElapsedTime();
|
||||
|
||||
@Override
|
||||
public void runOpMode() {
|
||||
|
||||
/*
|
||||
* Instantiate Arm
|
||||
*/
|
||||
ArmSubsystem arm = new ArmSubsystem(hardwareMap);
|
||||
|
||||
/*
|
||||
* Instantiate gamepad state holders
|
||||
*/
|
||||
Gamepad currentGamepad1 = new Gamepad();
|
||||
Gamepad previousGamepad1 = new Gamepad();
|
||||
|
||||
arm.initTeleOp();
|
||||
waitForStart();
|
||||
runtime.reset();
|
||||
|
||||
// run until the end of the match (driver presses STOP)
|
||||
while (opModeIsActive()) {
|
||||
|
||||
previousGamepad1.copy(currentGamepad1);
|
||||
currentGamepad1.copy(gamepad1);
|
||||
|
||||
if (currentGamepad1.circle && !previousGamepad1.circle) {
|
||||
arm.toParkPosition();
|
||||
}
|
||||
|
||||
if (currentGamepad1.square && !previousGamepad1.square) {
|
||||
arm.toBucketPosition();
|
||||
}
|
||||
|
||||
if (currentGamepad1.cross && !previousGamepad1.cross) {
|
||||
arm.toFloorPosition();
|
||||
}
|
||||
|
||||
if (currentGamepad1.left_bumper && !previousGamepad1.left_bumper) {
|
||||
arm.setPosition(arm.getPosition() - .05);
|
||||
}
|
||||
|
||||
if (currentGamepad1.right_bumper && !previousGamepad1.right_bumper) {
|
||||
arm.setPosition(arm.getPosition() + .05);
|
||||
}
|
||||
|
||||
telemetry.addData("Status", "Run Time: " + runtime.toString());
|
||||
telemetry.addData("Arm State", arm.getState());
|
||||
telemetry.addData("Arm Position", arm.getPosition());
|
||||
telemetry.update();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,85 +0,0 @@
|
||||
/* Copyright (c) 2021 FIRST. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted (subject to the limitations in the disclaimer below) 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 nor the names of its contributors may be used to endorse or
|
||||
* promote products derived from this software without specific prior written permission.
|
||||
*
|
||||
* NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS
|
||||
* LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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.
|
||||
*/
|
||||
|
||||
package org.firstinspires.ftc.teamcode.cometbots.tests;
|
||||
|
||||
import com.qualcomm.robotcore.eventloop.opmode.LinearOpMode;
|
||||
import com.qualcomm.robotcore.eventloop.opmode.TeleOp;
|
||||
import com.qualcomm.robotcore.hardware.Gamepad;
|
||||
import com.qualcomm.robotcore.util.ElapsedTime;
|
||||
|
||||
import org.firstinspires.ftc.teamcode.subsystem.ClawSubsystem;
|
||||
|
||||
|
||||
@TeleOp(name = "Claw Test v2", group = "Debug")
|
||||
public class ClawTest extends LinearOpMode {
|
||||
|
||||
// Declare OpMode members for each of the 4 motors.
|
||||
private final ElapsedTime runtime = new ElapsedTime();
|
||||
|
||||
@Override
|
||||
public void runOpMode() {
|
||||
|
||||
/*
|
||||
* Instantiate Claw
|
||||
*/
|
||||
ClawSubsystem claw = new ClawSubsystem(hardwareMap);
|
||||
|
||||
/*
|
||||
* Instantiate gamepad state holders
|
||||
*/
|
||||
Gamepad currentGamepad1 = new Gamepad();
|
||||
Gamepad previousGamepad1 = new Gamepad();
|
||||
|
||||
waitForStart();
|
||||
claw.init();
|
||||
runtime.reset();
|
||||
|
||||
// run until the end of the match (driver presses STOP)
|
||||
while (opModeIsActive()) {
|
||||
|
||||
previousGamepad1.copy(currentGamepad1);
|
||||
currentGamepad1.copy(gamepad1);
|
||||
|
||||
if (currentGamepad1.cross && !previousGamepad1.cross) {
|
||||
claw.switchState();
|
||||
}
|
||||
|
||||
if (currentGamepad1.triangle && !previousGamepad1.triangle) {
|
||||
claw.switchTState();
|
||||
}
|
||||
|
||||
// Show the elapsed game time and wheel power.
|
||||
telemetry.addData("Status", "Run Time: " + runtime.toString());
|
||||
telemetry.addData("Claw State", claw.getState());
|
||||
telemetry.addData("Claw Thumb State", claw.getTState());
|
||||
telemetry.update();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,72 +0,0 @@
|
||||
package org.firstinspires.ftc.teamcode.cometbots.tests;
|
||||
|
||||
import static org.firstinspires.ftc.teamcode.PedroConstants.LIFT_SLIDE_LEFT_MOTOR;
|
||||
import static org.firstinspires.ftc.teamcode.PedroConstants.LIFT_SLIDE_RIGHT_MOTOR;
|
||||
|
||||
import com.acmerobotics.dashboard.FtcDashboard;
|
||||
import com.acmerobotics.dashboard.config.Config;
|
||||
import com.acmerobotics.dashboard.telemetry.TelemetryPacket;
|
||||
import com.qualcomm.robotcore.eventloop.opmode.Autonomous;
|
||||
import com.qualcomm.robotcore.eventloop.opmode.LinearOpMode;
|
||||
import com.qualcomm.robotcore.hardware.DcMotor;
|
||||
import com.qualcomm.robotcore.hardware.DcMotorEx;
|
||||
import com.qualcomm.robotcore.util.ElapsedTime;
|
||||
|
||||
|
||||
@Config
|
||||
@Autonomous(name = "Lift Motor Subsystem - PID Test")
|
||||
public class DualMotorSliderTest extends LinearOpMode {
|
||||
|
||||
private DcMotorEx liftSlideLeft;
|
||||
private DcMotorEx liftSlideRight;
|
||||
public static double kp = 0.0015, ki = 0, kd = 0;
|
||||
private double lastError = 0;
|
||||
private double integralSum = 0;
|
||||
public static int targetPosition = 0;
|
||||
private final FtcDashboard dashboard = FtcDashboard.getInstance();
|
||||
private ElapsedTime timer = new ElapsedTime();
|
||||
|
||||
@Override
|
||||
public void runOpMode() throws InterruptedException {
|
||||
TelemetryPacket packet = new TelemetryPacket();
|
||||
dashboard.setTelemetryTransmissionInterval(25);
|
||||
|
||||
liftSlideLeft = hardwareMap.get(DcMotorEx.class, LIFT_SLIDE_LEFT_MOTOR);
|
||||
liftSlideRight = hardwareMap.get(DcMotorEx.class, LIFT_SLIDE_RIGHT_MOTOR);
|
||||
|
||||
liftSlideLeft.setMode(DcMotor.RunMode.STOP_AND_RESET_ENCODER);
|
||||
liftSlideLeft.setZeroPowerBehavior(DcMotor.ZeroPowerBehavior.BRAKE);
|
||||
liftSlideLeft.setMode(DcMotor.RunMode.RUN_WITHOUT_ENCODER);
|
||||
|
||||
liftSlideRight.setMode(DcMotor.RunMode.STOP_AND_RESET_ENCODER);
|
||||
liftSlideRight.setZeroPowerBehavior(DcMotor.ZeroPowerBehavior.BRAKE);
|
||||
liftSlideRight.setMode(DcMotor.RunMode.RUN_WITHOUT_ENCODER);
|
||||
|
||||
waitForStart();
|
||||
|
||||
while(opModeIsActive()) {
|
||||
double power = calculatePower(targetPosition, liftSlideLeft.getCurrentPosition());
|
||||
|
||||
packet.put("Power", power);
|
||||
packet.put("Position", liftSlideLeft.getCurrentPosition());
|
||||
packet.put("Error", lastError);
|
||||
packet.put("Seconds", timer.seconds());
|
||||
|
||||
liftSlideLeft.setPower(power);
|
||||
liftSlideRight.setPower(power);
|
||||
|
||||
dashboard.sendTelemetryPacket(packet);
|
||||
}
|
||||
}
|
||||
|
||||
private double calculatePower(int targetPosition, int currentPosition) {
|
||||
// reference is targetPosition, state is currentPosition
|
||||
double error = targetPosition - currentPosition;
|
||||
integralSum += error * timer.seconds();
|
||||
double derivative = (error - lastError) / timer.seconds();
|
||||
lastError = error;
|
||||
timer.reset();
|
||||
return (error * kp) + (derivative * kd) + (integralSum * ki);
|
||||
}
|
||||
|
||||
}
|
@ -1,93 +0,0 @@
|
||||
/* Copyright (c) 2021 FIRST. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted (subject to the limitations in the disclaimer below) 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 nor the names of its contributors may be used to endorse or
|
||||
* promote products derived from this software without specific prior written permission.
|
||||
*
|
||||
* NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS
|
||||
* LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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.
|
||||
*/
|
||||
|
||||
package org.firstinspires.ftc.teamcode.cometbots.tests;
|
||||
|
||||
import com.acmerobotics.roadrunner.ftc.Actions;
|
||||
import com.qualcomm.robotcore.eventloop.opmode.LinearOpMode;
|
||||
import com.qualcomm.robotcore.eventloop.opmode.TeleOp;
|
||||
import com.qualcomm.robotcore.hardware.Gamepad;
|
||||
import com.qualcomm.robotcore.util.ElapsedTime;
|
||||
|
||||
import org.firstinspires.ftc.teamcode.subsystem.WristSubsystem;
|
||||
|
||||
@TeleOp(name = "Wrist Test v2", group = "Debug")
|
||||
public class WristTest extends LinearOpMode {
|
||||
|
||||
// Declare OpMode members for each of the 4 motors.
|
||||
private final ElapsedTime runtime = new ElapsedTime();
|
||||
|
||||
@Override
|
||||
public void runOpMode() {
|
||||
|
||||
/*
|
||||
* Instantiate Wrist
|
||||
*/
|
||||
WristSubsystem wrist = new WristSubsystem(hardwareMap);
|
||||
|
||||
/*
|
||||
* Instantiate gamepad state holders
|
||||
*/
|
||||
Gamepad currentGamepad1 = new Gamepad();
|
||||
Gamepad previousGamepad1 = new Gamepad();
|
||||
|
||||
wrist.initTeleOp();
|
||||
waitForStart();
|
||||
runtime.reset();
|
||||
|
||||
// run until the end of the match (driver presses STOP)
|
||||
while (opModeIsActive()) {
|
||||
|
||||
previousGamepad1.copy(currentGamepad1);
|
||||
currentGamepad1.copy(gamepad1);
|
||||
|
||||
if (currentGamepad1.square && !previousGamepad1.square) {
|
||||
wrist.toBucketPosition();
|
||||
}
|
||||
|
||||
if (currentGamepad1.cross && !previousGamepad1.cross) {
|
||||
wrist.switchState();
|
||||
}
|
||||
|
||||
if (currentGamepad1.left_bumper && !previousGamepad1.left_bumper) {
|
||||
wrist.setPosition(wrist.getPosition() - .05);
|
||||
}
|
||||
|
||||
if (currentGamepad1.right_bumper && !previousGamepad1.right_bumper) {
|
||||
wrist.setPosition(wrist.getPosition() + .05);
|
||||
}
|
||||
|
||||
// Show the elapsed game time and wheel power.
|
||||
telemetry.addData("Status", "Run Time: " + runtime.toString());
|
||||
telemetry.addData("Wrist State", wrist.getState());
|
||||
telemetry.addData("Wrist Position", wrist.getPosition());
|
||||
telemetry.update();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
package org.firstinspires.ftc.teamcode.configs;
|
||||
|
||||
import com.acmerobotics.dashboard.config.Config;
|
||||
|
||||
@Config
|
||||
public class RobotConstants {
|
||||
public final static double clawClose = 0.95;
|
||||
public final static double clawOpen = 0.05;
|
||||
|
||||
public final static double armFloor = 0.7;
|
||||
public final static double armSubmarine = 0.55;
|
||||
public final static double armReverseBucket = 0.08;
|
||||
public final static double armPark = 0.33;
|
||||
//value for grabbing the hook Specimen
|
||||
public final static double grabBlueberry = 0.35;
|
||||
public final static double armGrabBlueberrySkyhook = 0.15;
|
||||
public final static double wristGrabBlueberrySkyhook = 0.15;
|
||||
public final static double armHangBlueberrySkyhook = 0.23;
|
||||
public final static double wristHangBlueberrySkyhook = 0.7;
|
||||
public final static int slideHangBlueberrySkyhook = 500;
|
||||
public final static int slideBelowFloor = -150;
|
||||
public final static int backwardBucketDrop = 4670;
|
||||
public final static double armBucket = 0.45;
|
||||
public final static double armInit = 0.135;
|
||||
public final static double wristInit = 0.25;
|
||||
public final static double wristPickup = 0.475;
|
||||
public final static double wristBucket = 0.56;
|
||||
public final static double wristFloor = 0.75;
|
||||
public final static double wristBackwardBucket = 0.775;
|
||||
|
||||
public final static double wristRung = 0.55;
|
||||
|
||||
public final static double wristSpeciemen = 0.1;
|
||||
|
||||
public final static int toBar = 500;
|
||||
public final static int toFloor = 0;
|
||||
public final static int liftToFloorPos = 350;
|
||||
public final static int liftToSubmarinePos = 350;
|
||||
public final static int liftToLowBucketPos = 1750;
|
||||
public final static int liftToHighRung = 2100;
|
||||
public final static int dropToHighRung = 1675;
|
||||
|
||||
public final static int liftToHighRungAttach = 1050;
|
||||
|
||||
|
||||
public final static int liftToHighBucketPos = 4000;
|
||||
public final static double liftPower = 1;
|
||||
}
|
@ -4,10 +4,10 @@ the pose exponential method of localization. It's basically a way of turning mov
|
||||
robot's coordinate frame to the global coordinate frame. If you're interested in reading more about
|
||||
it, then check out pages 177 - 183 of [Controls Engineering in the FIRST Robotics Competition](https://file.tavsys.net/control/controls-engineering-in-frc.pdf)
|
||||
by Tyler Veness. However, the OTOS localizer uses its own onboard system for calculating localization,
|
||||
which we do not know about.
|
||||
which I do not know about.
|
||||
|
||||
## Setting Your Localizer
|
||||
Go to line `73` in the `PoseUpdater` class, and replace the `new ThreeWheelLocalizer(hardwareMap)`
|
||||
Go to line `70` in the `PoseUpdater` class, and replace the `new ThreeWheelLocalizer(hardwareMap)`
|
||||
with the localizer that applies to you:
|
||||
* If you're using drive encoders, put `new DriveEncoderLocalizer(hardwareMap)`
|
||||
* If you're using two wheel odometry, put `new TwoWheelLocalizer(hardwareMap)`
|
||||
@ -15,7 +15,6 @@ with the localizer that applies to you:
|
||||
don't change it from the default
|
||||
* If you're using three wheel odometry with the IMU, put `new ThreeWheelIMULocalizer(hardwareMap)`
|
||||
* If you're using OTOS, put `new OTOSLocalizer(hardwareMap)`
|
||||
* If you're using Pinpoint, put `new PinpointLocalizer(hardwareMap)`
|
||||
|
||||
## Tuning
|
||||
To start, you'll want to select your localizer of choice. Below, I'll have instructions for the drive
|
||||
@ -242,23 +241,6 @@ that applies to you and follow the directions there.
|
||||
robot around and see if the movements look accurate on FTC Dashboard. If they don't, then you'll
|
||||
want to re-run some of the previous steps. Otherwise, congrats on tuning your localizer!
|
||||
|
||||
## Pinpoint Localizer
|
||||
* First you will need to plug in the pinpoint to the i2c port. Ensure that the dead wheel encoder wires are
|
||||
plugged into the proper ports on the pinpoint to ensure no error within the tuning steps.
|
||||
* Then, go to the `PinpointLocalier.java` file and go to where it tells you to replace
|
||||
the current statement with your pinpoint port in the constructor. Replace the `deviceName` parameter
|
||||
with the name of the port that the pinpoint is connected to.
|
||||
* Next, follow the instructions left by the TODO: comment and enter in the odometry measurements either in
|
||||
mms or inches (We have the conversion rates listed).
|
||||
* First, to ensure that your pinpoint is properly connected, please run the `SensorGoBildaPinpointExample.java`
|
||||
file left in the `tuning` folder located within `localization`.
|
||||
* Once completed, the localizer should be properly tuned. To test it out, you can go to
|
||||
`Localization Test` and push around or drive around your robot. Go to [FTC Dashboard](http://192.168.43.1:8080/dash)
|
||||
and on the top right, switch the drop down from the default view to the field view. Then, on the bottom
|
||||
left corner, you should see a field and the robot being drawn on the field. You can then move your
|
||||
robot around and see if the movements look accurate on FTC Dashboard. If they don't, then you'll
|
||||
want to re-run some of the previous steps. Otherwise, congrats on tuning your localizer!
|
||||
|
||||
## Using Road Runner's Localizer
|
||||
Of course, many teams have experience using Road Runner in the past and so have localizers from Road
|
||||
Runner that are tuned. There is an adapter for the Road Runner three wheel localizer to the Pedro
|
||||
|
@ -19,7 +19,7 @@ Why use Pedro Pathing? Why not something else like Road Runner or Pure Pursuit?
|
||||
* Pure Pursuit searches for the farthest point on the path that's within a certain radius from the robot. Pure Pursuit will then go in a straight line to that point. This poses several problems, as a small search radius will cause some oscillations on corners, and a large search radius will cut corners on paths, which makes the paths inaccurate to real life.
|
||||
* Pedro Pathing instead corrects to the closest point on the path while still following the path. This ensures that the follower will stay on the path while still being able to move forward along the path without cutting corners or encountering oscillation issues.
|
||||
* Why not Road Runner?
|
||||
* Road Runner is a motion profile based follower, which means that a set of instructions for motor powers are calculated for each path beforehand and then run. During this motion profile, Road Runner can struggle to correct. This can be sufficient for many situations, but if the robot encounters an obstacle or wheel slippage, it may be unable to correct in time.
|
||||
* Road Runner is a motion profile based follower, which means that a set of instructions for motor powers are calculated for each path beforehand and then run. After reaching the end of this motion profile, Road Runner corrects. This can be sufficient for most situations, but if the robot encounters an obstacle or wheel slippage, it may be unable to correct in time.
|
||||
* Pedro Pathing instead dynamically corrects throughout the path. The movement vectors are calculated at every point along the path, and because of this, the path can even be changed midway through and Pedro Pathing will still be able to correct. Since correction occurs throughout the path, the error correction isn't concentrated on the end of the path and therefore the robot is able to better minimize error.
|
||||
|
||||
## How Does Pedro Path?
|
||||
@ -105,5 +105,4 @@ of the curvature formula, we can estimate a centripetal force correction and app
|
||||
control.
|
||||
|
||||
## Questions?
|
||||
If you still have more questions, feel free to contact us at `scottsbots10158@gmail.com` or
|
||||
within our discord linked here(https://discord.gg/2GfC4qBP5s)
|
||||
If you still have more questions, feel free to contact us at `scottsbots10158@gmail.com`
|
@ -14,56 +14,45 @@ that the tuners require you to push the robot or the tuners output will say "inc
|
||||
measurements will be in centimeters.
|
||||
|
||||
## Tuning
|
||||
* First, make sure that your motor names and directions, located at the top of `FollowerConstants`,
|
||||
are correct.
|
||||
|
||||
* After that, we need the mass of the robot in kg. This is used for the centripetal force correction,
|
||||
and the mass, with the variable name `mass`, should be put on line `92` in the `FollowerConstants`
|
||||
* To start with, we need the mass of the robot in kg. This is used for the centripetal force correction,
|
||||
and the mass, with the variable name `mass`, should be put on line `86` in the `FollowerConstants`
|
||||
class under the `tuning` package.
|
||||
|
||||
* Next, we need to find the preferred mecanum drive vectors. The rollers on mecanum wheels point at a
|
||||
45 degree angle from the forward direction, but the actual direction the force is output is actually
|
||||
closer to forward. Before running any OpModes, make sure your motors are reversed properly in the
|
||||
`Follower` class constructor. To find the direction your wheels will go, you will need to run the
|
||||
closer to forward. To find the direction your wheels will go, you will need to run the
|
||||
`Forward Velocity Tuner` and `Strafe Velocity Tuner` OpModes. These will run your robot at full
|
||||
power for 40 inches forward and to the right, respectively. The distance can be changed through FTC
|
||||
Dashboard under the dropdown for each respective class, but higher distances work better. After the
|
||||
distance has finished running, the end velocity will be output to telemetry. The robot may continue
|
||||
to drift a little bit after the robot has finished running the distance, so make sure you have
|
||||
plenty of room. Once you're done, put the velocity for the `Forward Velocity Tuner` on line `39` in
|
||||
the `FollowerConstants` class, and the velocity for the `Strafe Velocity Tuner` on line `40` in the
|
||||
plenty of room. Once you're done, put the velocity for the `Forward Velocity Tuner` on line `33` in
|
||||
the `FollowerConstants` class, and the velocity for the `Strafe Velocity Tuner` on line `34` in the
|
||||
`FollowerConstants` class. The variable names should be `xMovement` and `yMovement`, respectively.
|
||||
|
||||
* The last set of automatic tuners you'll need to run are the zero power acceleration tuners. These
|
||||
find the rate at which your robot decelerates when power is cut from the drivetrain. This is used to
|
||||
get a more accurate estimation of the drive vector. To find this, you will need to run the
|
||||
`Forward Zero Power Acceleration Tuner` and the `Lateral Zero Power Acceleration Tuner` OpModes.
|
||||
These will run your robot until it hits a velocity of 30 inches/second forward and to the right,
|
||||
These will run your robot until it hits a velocity of 10 inches/second forward and to the right,
|
||||
respectively. The velocity can be changed through FTC Dashboard under the dropdown for each
|
||||
respective class, but higher velocities work better. After the velocity has been reached, power will
|
||||
be cut from the drivetrain and the robot's deceleration will be tracked until the robot stops, at
|
||||
which point it will display the deceleration in telemetry. This robot will need to drift to a stop
|
||||
to properly work, and the higher the velocity the greater the drift distance, so make sure you have
|
||||
enough room. Once you're done, put the zero power acceleration for the
|
||||
`Forward Zero Power Acceleration Tuner` on line `100` in the `FollowerConstants` class and the zero
|
||||
power acceleration for the `Lateral Zero Power Acceleration Tuner` on line `104` in the
|
||||
`Forward Zero Power Acceleration Tuner` on line `94` in the `FollowerConstants` class and the zero
|
||||
power acceleration for the `Lateral Zero Power Acceleration Tuner` on line `98` in the
|
||||
`FollowerConstants` class. The variable names should be `forwardZeroPowerAcceleration` and
|
||||
`lateralZeroPowerAcceleration`, respectively.
|
||||
|
||||
* After this, we will want to tune the translational PID. Go to FTC Dashboard and disable all but
|
||||
the `useTranslational` checkboxes under the `Follower` tab. Then, run `StraightBackAndForth`.
|
||||
Make sure you disable the timer on autonomous OpModes. You will notice in telemetry a message saying
|
||||
that the robot will travel a distance forward and backward, this will not happen until later, so for
|
||||
now you can ignore this message. The robot should not move when you run the opmode initally. Instead,
|
||||
it should correct when you push it away from its starting position. Note that this correction should
|
||||
happen regardless of the robot's rotation, and that the robot should not rotate itself (if it does,
|
||||
disable `useHeading` as mentioned prior). Also note that the robot will only correct to an imaginary line
|
||||
that runs straight forward from the robot's starting position, meaning that it will not correct in the
|
||||
(original) forward direction. The PID for the translational error is called `translationalPIDF`.
|
||||
If you need to add a feedforward value, use the `translationalPIDFFeedForward` since that will add
|
||||
the feedforward in the direction the robot is trying to move, rather than the feedforward in the
|
||||
PIDF itself, since those will only add the feedforward one way. You can change the PIDF constants
|
||||
and feedforward values, under the `FollowerConstants` tab in FTC Dashboard.
|
||||
the `useTranslational` checkboxes under the `Follower` tab. Then, run `StraightBackAndForth`. Make
|
||||
sure you disable the timer on autonomous OpModes. The PID for the translational error is called
|
||||
`translationalPIDF`. If you need to add a feedforward value, use the `translationalPIDFFeedForward`
|
||||
since that will add the feedforward in the direction the robot is trying to move, rather than the
|
||||
feedforward in the PIDF itself, since those will only add the feedforward one way. You can change
|
||||
the PIDF constants and feedforward values, under the `FollowerConstants` tab in FTC Dashboard.
|
||||
To tune the PID, push the robot off the path and see how corrects. You will want to alternate sides
|
||||
you push to reduce field wear and tear as well as push with varying power and distance. I would
|
||||
recommend tuning the PID so that it is capable of correcting while minimizing oscillations and still
|
||||
@ -81,8 +70,9 @@ measurements will be in centimeters.
|
||||
`zeroPowerAccelerationMultiplier`. This determines how fast your robot will decelerate as a factor
|
||||
of how fast your robot will coast to a stop. Honestly, this is up to you. I personally used 4, but
|
||||
what works best for you is most important. Higher numbers will cause a faster brake, but increase
|
||||
oscillations at the end. Lower numbers will do the opposite. This can be found on line `113` in
|
||||
`FollowerConstants`, named `zeroPowerAccelerationMultiplier`. The drive PID is much, much more sensitive than the others. For reference,
|
||||
oscillations at the end. Lower numbers will do the opposite. This can be found on line `107` in
|
||||
`FollowerConstants`, named `zeroPowerAccelerationMultiplier`. The drive PID is much, much more
|
||||
* sensitive than the others. For reference,
|
||||
my P values were in the hundredths and thousandths place values, and my D values were in the hundred
|
||||
thousandths and millionths place values. To tune this, enable `useDrive`, `useHeading`, and
|
||||
`useTranslational` in the `Follower` dropdown in FTC Dashboard. Next, run `StraightBackAndForth`
|
||||
@ -107,7 +97,7 @@ measurements will be in centimeters.
|
||||
* Finally, we will want to tune the centripetal force correction. This is a pretty simple tune. Open
|
||||
up FTC Dashboard and enable everything under the `Follower` tab. Then, run `CurvedBackAndForth`
|
||||
and turn off its timer. If you notice the robot is correcting towards the inside of the curve
|
||||
as/after running a path, then increase `centripetalScaling`, which can be found on line `95` of
|
||||
as/after running a path, then increase `centripetalScaling`, which can be found on line `89` of
|
||||
`FollowerConstants`. If the robot is correcting towards the outside of the curve, then decrease
|
||||
`centripetalScaling`.
|
||||
|
||||
@ -120,7 +110,7 @@ measurements will be in centimeters.
|
||||
## Note About the PIDs
|
||||
In versions of Pedro Pathing before early August 2024, there were 2 PIDs used in the translational,
|
||||
heading, and drive control. However, now there is only one main PID. The old system can still be used.
|
||||
Scroll down to the bottom of `FollowerConstants` and set all the booleans from lines `163` to `165`
|
||||
Scroll down to the bottom of `FollowerConstants` and set all the booleans from lines `157` to `159`
|
||||
to true. They should be named `useSecondaryTranslationalPID`, `useSecondaryHeadingPID`, and `useSecondaryDrivePID`.
|
||||
This will enable the two PID system that Pedro Pathing originally used. From there, scroll
|
||||
down and all the values pertaining to the secondary PIDs will be there. The two PID system works with
|
||||
|
@ -15,7 +15,6 @@ import org.firstinspires.ftc.teamcode.pedroPathing.pathGeneration.Vector;
|
||||
public class DriveVectorScaler {
|
||||
// This is ordered left front, left back, right front, right back. These are also normalized.
|
||||
private Vector[] mecanumVectors;
|
||||
private double maxPowerScaling = 1;
|
||||
|
||||
/**
|
||||
* This creates a new DriveVectorScaler, which takes in various movement vectors and outputs
|
||||
@ -53,9 +52,9 @@ public class DriveVectorScaler {
|
||||
*/
|
||||
public double[] getDrivePowers(Vector correctivePower, Vector headingPower, Vector pathingPower, double robotHeading) {
|
||||
// clamps down the magnitudes of the input vectors
|
||||
if (correctivePower.getMagnitude() > maxPowerScaling) correctivePower.setMagnitude(maxPowerScaling);
|
||||
if (headingPower.getMagnitude() > maxPowerScaling) headingPower.setMagnitude(maxPowerScaling);
|
||||
if (pathingPower.getMagnitude() > maxPowerScaling) pathingPower.setMagnitude(maxPowerScaling);
|
||||
if (correctivePower.getMagnitude() > 1) correctivePower.setMagnitude(1);
|
||||
if (headingPower.getMagnitude() > 1) headingPower.setMagnitude(1);
|
||||
if (pathingPower.getMagnitude() > 1) pathingPower.setMagnitude(1);
|
||||
|
||||
// the powers for the wheel vectors
|
||||
double [] wheelPowers = new double[4];
|
||||
@ -66,8 +65,8 @@ public class DriveVectorScaler {
|
||||
// this contains the pathing vectors, one for each side (heading control requires 2)
|
||||
Vector[] truePathingVectors = new Vector[2];
|
||||
|
||||
if (correctivePower.getMagnitude() == maxPowerScaling) {
|
||||
// checks for corrective power equal to max power scaling in magnitude. if equal, then set pathing power to that
|
||||
if (correctivePower.getMagnitude() == 1) {
|
||||
// checks for corrective power equal to 1 in magnitude. if equal to one, then set pathing power to that
|
||||
truePathingVectors[0] = MathFunctions.copyVector(correctivePower);
|
||||
truePathingVectors[1] = MathFunctions.copyVector(correctivePower);
|
||||
} else {
|
||||
@ -75,7 +74,7 @@ public class DriveVectorScaler {
|
||||
Vector leftSideVector = MathFunctions.subtractVectors(correctivePower, headingPower);
|
||||
Vector rightSideVector = MathFunctions.addVectors(correctivePower, headingPower);
|
||||
|
||||
if (leftSideVector.getMagnitude() > maxPowerScaling || rightSideVector.getMagnitude() > maxPowerScaling) {
|
||||
if (leftSideVector.getMagnitude() > 1 || rightSideVector.getMagnitude() > 1) {
|
||||
//if the combined corrective and heading power is greater than 1, then scale down heading power
|
||||
double headingScalingFactor = Math.min(findNormalizingScaling(correctivePower, headingPower), findNormalizingScaling(correctivePower, MathFunctions.scalarMultiplyVector(headingPower, -1)));
|
||||
truePathingVectors[0] = MathFunctions.subtractVectors(correctivePower, MathFunctions.scalarMultiplyVector(headingPower, headingScalingFactor));
|
||||
@ -85,7 +84,7 @@ public class DriveVectorScaler {
|
||||
Vector leftSideVectorWithPathing = MathFunctions.addVectors(leftSideVector, pathingPower);
|
||||
Vector rightSideVectorWithPathing = MathFunctions.addVectors(rightSideVector, pathingPower);
|
||||
|
||||
if (leftSideVectorWithPathing.getMagnitude() > maxPowerScaling || rightSideVectorWithPathing.getMagnitude() > maxPowerScaling) {
|
||||
if (leftSideVectorWithPathing.getMagnitude() > 1 || rightSideVectorWithPathing.getMagnitude() > 1) {
|
||||
// too much power now, so we scale down the pathing vector
|
||||
double pathingScalingFactor = Math.min(findNormalizingScaling(leftSideVector, pathingPower), findNormalizingScaling(rightSideVector, pathingPower));
|
||||
truePathingVectors[0] = MathFunctions.addVectors(leftSideVector, MathFunctions.scalarMultiplyVector(pathingPower, pathingScalingFactor));
|
||||
@ -114,7 +113,7 @@ public class DriveVectorScaler {
|
||||
wheelPowers[3] = (mecanumVectorsCopy[2].getXComponent()*truePathingVectors[1].getYComponent() - truePathingVectors[1].getXComponent()*mecanumVectorsCopy[2].getYComponent()) / (mecanumVectorsCopy[2].getXComponent()*mecanumVectorsCopy[3].getYComponent() - mecanumVectorsCopy[3].getXComponent()*mecanumVectorsCopy[2].getYComponent());
|
||||
|
||||
double wheelPowerMax = Math.max(Math.max(Math.abs(wheelPowers[0]), Math.abs(wheelPowers[1])), Math.max(Math.abs(wheelPowers[2]), Math.abs(wheelPowers[3])));
|
||||
if (wheelPowerMax > maxPowerScaling) {
|
||||
if (wheelPowerMax > 1) {
|
||||
wheelPowers[0] /= wheelPowerMax;
|
||||
wheelPowers[1] /= wheelPowerMax;
|
||||
wheelPowers[2] /= wheelPowerMax;
|
||||
@ -127,12 +126,12 @@ public class DriveVectorScaler {
|
||||
/**
|
||||
* This takes in two Vectors, one static and one variable, and returns the scaling factor that,
|
||||
* when multiplied to the variable Vector, results in magnitude of the sum of the static Vector
|
||||
* and the scaled variable Vector being the max power scaling.
|
||||
* and the scaled variable Vector being 1.
|
||||
*
|
||||
* IMPORTANT NOTE: I did not intend for this to be used for anything other than the method above
|
||||
* this one in this class, so there will be errors if you input Vectors of length greater than maxPowerScaling,
|
||||
* this one in this class, so there will be errors if you input Vectors of length greater than 1,
|
||||
* and it will scale up the variable Vector if the magnitude of the sum of the two input Vectors
|
||||
* isn't greater than maxPowerScaling. So, just don't use this elsewhere. There's gotta be a better way to do
|
||||
* isn't greater than 1. So, just don't use this elsewhere. There's gotta be a better way to do
|
||||
* whatever you're trying to do.
|
||||
*
|
||||
* I know that this is used outside of this class, however, I created this method so I get to
|
||||
@ -141,32 +140,13 @@ public class DriveVectorScaler {
|
||||
*
|
||||
* @param staticVector the Vector that is held constant.
|
||||
* @param variableVector the Vector getting scaled to make the sum of the input Vectors have a
|
||||
* magnitude of maxPowerScaling.
|
||||
* magnitude of 1.
|
||||
* @return returns the scaling factor for the variable Vector.
|
||||
*/
|
||||
public double findNormalizingScaling(Vector staticVector, Vector variableVector) {
|
||||
double a = Math.pow(variableVector.getXComponent(), 2) + Math.pow(variableVector.getYComponent(), 2);
|
||||
double b = staticVector.getXComponent() * variableVector.getXComponent() + staticVector.getYComponent() * variableVector.getYComponent();
|
||||
double c = Math.pow(staticVector.getXComponent(), 2) + Math.pow(staticVector.getYComponent(), 2) - Math.pow(maxPowerScaling, 2);
|
||||
double c = Math.pow(staticVector.getXComponent(), 2) + Math.pow(staticVector.getYComponent(), 2) - 1.0;
|
||||
return (-b + Math.sqrt(Math.pow(b, 2) - a*c))/(a);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum power that can be used by the drive vector scaler. Clamped between 0 and 1.
|
||||
*
|
||||
* @param maxPowerScaling setting the max power scaling
|
||||
*/
|
||||
public void setMaxPowerScaling(double maxPowerScaling) {
|
||||
this.maxPowerScaling = MathFunctions.clamp(maxPowerScaling, 0, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the maximum power that can be used by the drive vector scaler. Ranges between 0 and 1.
|
||||
*
|
||||
* @return returns the max power scaling
|
||||
*/
|
||||
public double getMaxPowerScaling() {
|
||||
return maxPowerScaling;
|
||||
}
|
||||
}
|
||||
|
@ -1,23 +1,20 @@
|
||||
package org.firstinspires.ftc.teamcode.pedroPathing.follower;
|
||||
|
||||
import static org.firstinspires.ftc.teamcode.PedroConstants.BACK_LEFT_MOTOR_DIRECTION;
|
||||
import static org.firstinspires.ftc.teamcode.PedroConstants.BACK_RIGHT_MOTOR_DIRECTION;
|
||||
import static org.firstinspires.ftc.teamcode.PedroConstants.FRONT_LEFT_MOTOR_DIRECTION;
|
||||
import static org.firstinspires.ftc.teamcode.PedroConstants.FRONT_RIGHT_MOTOR_DIRECTION;
|
||||
import static org.firstinspires.ftc.teamcode.pedroPathing.tuning.FollowerConstants.drivePIDFFeedForward;
|
||||
import static org.firstinspires.ftc.teamcode.PedroConstants.*;
|
||||
import static org.firstinspires.ftc.teamcode.pedroPathing.tuning.FollowerConstants.drivePIDFSwitch;
|
||||
import static org.firstinspires.ftc.teamcode.pedroPathing.tuning.FollowerConstants.forwardZeroPowerAcceleration;
|
||||
import static org.firstinspires.ftc.teamcode.pedroPathing.tuning.FollowerConstants.headingPIDFFeedForward;
|
||||
import static org.firstinspires.ftc.teamcode.pedroPathing.tuning.FollowerConstants.headingPIDFSwitch;
|
||||
import static org.firstinspires.ftc.teamcode.pedroPathing.tuning.FollowerConstants.lateralZeroPowerAcceleration;
|
||||
import static org.firstinspires.ftc.teamcode.pedroPathing.tuning.FollowerConstants.drivePIDFFeedForward;
|
||||
import static org.firstinspires.ftc.teamcode.pedroPathing.tuning.FollowerConstants.headingPIDFFeedForward;
|
||||
import static org.firstinspires.ftc.teamcode.pedroPathing.tuning.FollowerConstants.leftFrontMotorName;
|
||||
import static org.firstinspires.ftc.teamcode.pedroPathing.tuning.FollowerConstants.leftRearMotorName;
|
||||
import static org.firstinspires.ftc.teamcode.pedroPathing.tuning.FollowerConstants.rightFrontMotorName;
|
||||
import static org.firstinspires.ftc.teamcode.pedroPathing.tuning.FollowerConstants.rightRearMotorName;
|
||||
import static org.firstinspires.ftc.teamcode.pedroPathing.tuning.FollowerConstants.translationalPIDFFeedForward;
|
||||
import static org.firstinspires.ftc.teamcode.pedroPathing.tuning.FollowerConstants.lateralZeroPowerAcceleration;
|
||||
import static org.firstinspires.ftc.teamcode.pedroPathing.tuning.FollowerConstants.secondaryDrivePIDFFeedForward;
|
||||
import static org.firstinspires.ftc.teamcode.pedroPathing.tuning.FollowerConstants.secondaryHeadingPIDFFeedForward;
|
||||
import static org.firstinspires.ftc.teamcode.pedroPathing.tuning.FollowerConstants.secondaryTranslationalPIDFFeedForward;
|
||||
import static org.firstinspires.ftc.teamcode.pedroPathing.tuning.FollowerConstants.translationalPIDFFeedForward;
|
||||
import static org.firstinspires.ftc.teamcode.pedroPathing.tuning.FollowerConstants.translationalPIDFSwitch;
|
||||
import static org.firstinspires.ftc.teamcode.pedroPathing.tuning.FollowerConstants.useSecondaryDrivePID;
|
||||
import static org.firstinspires.ftc.teamcode.pedroPathing.tuning.FollowerConstants.useSecondaryHeadingPID;
|
||||
@ -27,6 +24,7 @@ import com.acmerobotics.dashboard.config.Config;
|
||||
import com.acmerobotics.dashboard.telemetry.MultipleTelemetry;
|
||||
import com.qualcomm.robotcore.hardware.DcMotor;
|
||||
import com.qualcomm.robotcore.hardware.DcMotorEx;
|
||||
import com.qualcomm.robotcore.hardware.DcMotorSimple;
|
||||
import com.qualcomm.robotcore.hardware.HardwareMap;
|
||||
import com.qualcomm.robotcore.hardware.configuration.typecontainers.MotorConfigurationType;
|
||||
|
||||
@ -96,6 +94,7 @@ public class Follower {
|
||||
private boolean holdPositionAtEnd;
|
||||
private boolean teleopDrive;
|
||||
|
||||
private double maxPower = 1;
|
||||
private double previousSecondaryTranslationalIntegral;
|
||||
private double previousTranslationalIntegral;
|
||||
private double holdPointTranslationalScaling = FollowerConstants.holdPointTranslationalScaling;
|
||||
@ -154,16 +153,6 @@ public class Follower {
|
||||
initialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* This creates a new Follower given a HardwareMap and a localizer.
|
||||
* @param hardwareMap HardwareMap required
|
||||
* @param localizer the localizer you wish to use
|
||||
*/
|
||||
// public Follower(HardwareMap hardwareMap, Localizer localizer) {
|
||||
// this.hardwareMap = hardwareMap;
|
||||
// initialize(localizer);
|
||||
// }
|
||||
|
||||
/**
|
||||
* This initializes the follower.
|
||||
* In this, the DriveVectorScaler and PoseUpdater is instantiated, the drive motors are
|
||||
@ -208,7 +197,18 @@ public class Follower {
|
||||
* @param set This caps the motor power from [0, 1].
|
||||
*/
|
||||
public void setMaxPower(double set) {
|
||||
driveVectorScaler.setMaxPowerScaling(set);
|
||||
maxPower = MathFunctions.clamp(set, 0, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* This handles the limiting of the drive powers array to the max power.
|
||||
*/
|
||||
public void limitDrivePowers() {
|
||||
for (int i = 0; i < drivePowers.length; i++) {
|
||||
if (Math.abs(drivePowers[i]) > maxPower) {
|
||||
drivePowers[i] = maxPower * MathFunctions.getSign(drivePowers[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -368,25 +368,6 @@ public class Follower {
|
||||
closestPose = currentPath.getClosestPoint(poseUpdater.getPose(), 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* This holds a Point.
|
||||
*
|
||||
* @param point the Point to stay at.
|
||||
* @param heading the heading to face.
|
||||
*/
|
||||
public void holdPoint(Point point, double heading) {
|
||||
holdPoint(new BezierPoint(point), heading);
|
||||
}
|
||||
|
||||
/**
|
||||
* This holds a Point.
|
||||
*
|
||||
* @param pose the Point (as a Pose) to stay at.
|
||||
*/
|
||||
public void holdPoint(Pose pose) {
|
||||
holdPoint(new Point(pose), pose.getHeading());
|
||||
}
|
||||
|
||||
/**
|
||||
* This follows a Path.
|
||||
* This also makes the Follower hold the last Point on the Path.
|
||||
@ -448,22 +429,15 @@ public class Follower {
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls an update to the PoseUpdater, which updates the robot's current position estimate.
|
||||
* This calls an update to the PoseUpdater, which updates the robot's current position estimate.
|
||||
* This also updates all the Follower's PIDFs, which updates the motor powers.
|
||||
*/
|
||||
public void updatePose() {
|
||||
public void update() {
|
||||
poseUpdater.update();
|
||||
|
||||
if (drawOnDashboard) {
|
||||
dashboardPoseTracker.update();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This calls an update to the PoseUpdater, which updates the robot's current position estimate.
|
||||
* This also updates all the Follower's PIDFs, which updates the motor powers.
|
||||
*/
|
||||
public void update() {
|
||||
updatePose();
|
||||
|
||||
if (!teleopDrive) {
|
||||
if (currentPath != null) {
|
||||
@ -472,6 +446,8 @@ public class Follower {
|
||||
|
||||
drivePowers = driveVectorScaler.getDrivePowers(MathFunctions.scalarMultiplyVector(getTranslationalCorrection(), holdPointTranslationalScaling), MathFunctions.scalarMultiplyVector(getHeadingVector(), holdPointHeadingScaling), new Vector(), poseUpdater.getPose().getHeading());
|
||||
|
||||
limitDrivePowers();
|
||||
|
||||
for (int i = 0; i < motors.size(); i++) {
|
||||
motors.get(i).setPower(drivePowers[i]);
|
||||
}
|
||||
@ -483,6 +459,8 @@ public class Follower {
|
||||
|
||||
drivePowers = driveVectorScaler.getDrivePowers(getCorrectiveVector(), getHeadingVector(), getDriveVector(), poseUpdater.getPose().getHeading());
|
||||
|
||||
limitDrivePowers();
|
||||
|
||||
for (int i = 0; i < motors.size(); i++) {
|
||||
motors.get(i).setPower(drivePowers[i]);
|
||||
}
|
||||
@ -525,6 +503,8 @@ public class Follower {
|
||||
|
||||
drivePowers = driveVectorScaler.getDrivePowers(getCentripetalForceCorrection(), teleopHeadingVector, teleopDriveVector, poseUpdater.getPose().getHeading());
|
||||
|
||||
limitDrivePowers();
|
||||
|
||||
for (int i = 0; i < motors.size(); i++) {
|
||||
motors.get(i).setPower(drivePowers[i]);
|
||||
}
|
||||
@ -538,7 +518,7 @@ public class Follower {
|
||||
* movement, this is the x-axis.
|
||||
* @param lateralDrive determines the lateral drive vector for the robot in teleop. In field centric
|
||||
* movement, this is the y-axis.
|
||||
* @param heading determines the heading vector for the robot in teleop.
|
||||
* @param heading determines the heading vector for the robot in teleop.
|
||||
*/
|
||||
public void setTeleOpMovementVectors(double forwardDrive, double lateralDrive, double heading) {
|
||||
setTeleOpMovementVectors(forwardDrive, lateralDrive, heading, true);
|
||||
@ -551,7 +531,7 @@ public class Follower {
|
||||
* movement, this is the x-axis.
|
||||
* @param lateralDrive determines the lateral drive vector for the robot in teleop. In field centric
|
||||
* movement, this is the y-axis.
|
||||
* @param heading determines the heading vector for the robot in teleop.
|
||||
* @param heading determines the heading vector for the robot in teleop.
|
||||
* @param robotCentric sets if the movement will be field or robot centric
|
||||
*/
|
||||
public void setTeleOpMovementVectors(double forwardDrive, double lateralDrive, double heading, boolean robotCentric) {
|
||||
@ -690,19 +670,19 @@ public class Follower {
|
||||
public Vector getDriveVector() {
|
||||
if (!useDrive) return new Vector();
|
||||
if (followingPathChain && chainIndex < currentPathChain.size() - 1) {
|
||||
return new Vector(driveVectorScaler.getMaxPowerScaling(), currentPath.getClosestPointTangentVector().getTheta());
|
||||
return new Vector(1, currentPath.getClosestPointTangentVector().getTheta());
|
||||
}
|
||||
|
||||
driveError = getDriveVelocityError();
|
||||
|
||||
if (Math.abs(driveError) < drivePIDFSwitch && useSecondaryDrivePID) {
|
||||
secondaryDrivePIDF.updateError(driveError);
|
||||
driveVector = new Vector(MathFunctions.clamp(secondaryDrivePIDF.runPIDF() + secondaryDrivePIDFFeedForward * MathFunctions.getSign(driveError), -driveVectorScaler.getMaxPowerScaling(), driveVectorScaler.getMaxPowerScaling()), currentPath.getClosestPointTangentVector().getTheta());
|
||||
driveVector = new Vector(MathFunctions.clamp(secondaryDrivePIDF.runPIDF() + secondaryDrivePIDFFeedForward * MathFunctions.getSign(driveError), -1, 1), currentPath.getClosestPointTangentVector().getTheta());
|
||||
return MathFunctions.copyVector(driveVector);
|
||||
}
|
||||
|
||||
drivePIDF.updateError(driveError);
|
||||
driveVector = new Vector(MathFunctions.clamp(drivePIDF.runPIDF() + drivePIDFFeedForward * MathFunctions.getSign(driveError), -driveVectorScaler.getMaxPowerScaling(), driveVectorScaler.getMaxPowerScaling()), currentPath.getClosestPointTangentVector().getTheta());
|
||||
driveVector = new Vector(MathFunctions.clamp(drivePIDF.runPIDF() + drivePIDFFeedForward * MathFunctions.getSign(driveError), -1, 1), currentPath.getClosestPointTangentVector().getTheta());
|
||||
return MathFunctions.copyVector(driveVector);
|
||||
}
|
||||
|
||||
@ -742,7 +722,7 @@ public class Follower {
|
||||
Vector velocityErrorVector = MathFunctions.addVectors(forwardVelocityError, lateralVelocityError);
|
||||
|
||||
previousRawDriveError = rawDriveError;
|
||||
rawDriveError = velocityErrorVector.getMagnitude() * MathFunctions.getSign(MathFunctions.dotProduct(velocityErrorVector, currentPath.getClosestPointTangentVector()));
|
||||
rawDriveError = velocityErrorVector.getMagnitude() * MathFunctions.getSign(MathFunctions.dotProduct(velocityErrorVector, currentPath.getClosestPointTangentVector()));
|
||||
|
||||
double projection = 2 * driveErrors[1] - driveErrors[0];
|
||||
|
||||
@ -771,11 +751,11 @@ public class Follower {
|
||||
headingError = MathFunctions.getTurnDirection(poseUpdater.getPose().getHeading(), currentPath.getClosestPointHeadingGoal()) * MathFunctions.getSmallestAngleDifference(poseUpdater.getPose().getHeading(), currentPath.getClosestPointHeadingGoal());
|
||||
if (Math.abs(headingError) < headingPIDFSwitch && useSecondaryHeadingPID) {
|
||||
secondaryHeadingPIDF.updateError(headingError);
|
||||
headingVector = new Vector(MathFunctions.clamp(secondaryHeadingPIDF.runPIDF() + secondaryHeadingPIDFFeedForward * MathFunctions.getTurnDirection(poseUpdater.getPose().getHeading(), currentPath.getClosestPointHeadingGoal()), -driveVectorScaler.getMaxPowerScaling(), driveVectorScaler.getMaxPowerScaling()), poseUpdater.getPose().getHeading());
|
||||
headingVector = new Vector(MathFunctions.clamp(secondaryHeadingPIDF.runPIDF() + secondaryHeadingPIDFFeedForward * MathFunctions.getTurnDirection(poseUpdater.getPose().getHeading(), currentPath.getClosestPointHeadingGoal()), -1, 1), poseUpdater.getPose().getHeading());
|
||||
return MathFunctions.copyVector(headingVector);
|
||||
}
|
||||
headingPIDF.updateError(headingError);
|
||||
headingVector = new Vector(MathFunctions.clamp(headingPIDF.runPIDF() + headingPIDFFeedForward * MathFunctions.getTurnDirection(poseUpdater.getPose().getHeading(), currentPath.getClosestPointHeadingGoal()), -driveVectorScaler.getMaxPowerScaling(), driveVectorScaler.getMaxPowerScaling()), poseUpdater.getPose().getHeading());
|
||||
headingVector = new Vector(MathFunctions.clamp(headingPIDF.runPIDF() + headingPIDFFeedForward * MathFunctions.getTurnDirection(poseUpdater.getPose().getHeading(), currentPath.getClosestPointHeadingGoal()), -1, 1), poseUpdater.getPose().getHeading());
|
||||
return MathFunctions.copyVector(headingVector);
|
||||
}
|
||||
|
||||
@ -792,7 +772,7 @@ public class Follower {
|
||||
Vector translational = getTranslationalCorrection();
|
||||
Vector corrective = MathFunctions.addVectors(centripetal, translational);
|
||||
|
||||
if (corrective.getMagnitude() > driveVectorScaler.getMaxPowerScaling()) {
|
||||
if (corrective.getMagnitude() > 1) {
|
||||
return MathFunctions.addVectors(centripetal, MathFunctions.scalarMultiplyVector(translational, driveVectorScaler.findNormalizingScaling(centripetal, translational)));
|
||||
}
|
||||
|
||||
@ -841,7 +821,7 @@ public class Follower {
|
||||
translationalVector = MathFunctions.addVectors(translationalVector, translationalIntegralVector);
|
||||
}
|
||||
|
||||
translationalVector.setMagnitude(MathFunctions.clamp(translationalVector.getMagnitude(), 0, driveVectorScaler.getMaxPowerScaling()));
|
||||
translationalVector.setMagnitude(MathFunctions.clamp(translationalVector.getMagnitude(), 0, 1));
|
||||
|
||||
this.translationalVector = MathFunctions.copyVector(translationalVector);
|
||||
|
||||
@ -880,7 +860,7 @@ public class Follower {
|
||||
curvature = (yDoublePrime) / (Math.pow(Math.sqrt(1 + Math.pow(yPrime, 2)), 3));
|
||||
}
|
||||
if (Double.isNaN(curvature)) return new Vector();
|
||||
centripetalVector = new Vector(MathFunctions.clamp(FollowerConstants.centripetalScaling * FollowerConstants.mass * Math.pow(MathFunctions.dotProduct(poseUpdater.getVelocity(), MathFunctions.normalizeVector(currentPath.getClosestPointTangentVector())), 2) * curvature, -driveVectorScaler.getMaxPowerScaling(), driveVectorScaler.getMaxPowerScaling()), currentPath.getClosestPointTangentVector().getTheta() + Math.PI / 2 * MathFunctions.getSign(currentPath.getClosestPointNormalVector().getTheta()));
|
||||
centripetalVector = new Vector(MathFunctions.clamp(FollowerConstants.centripetalScaling * FollowerConstants.mass * Math.pow(MathFunctions.dotProduct(poseUpdater.getVelocity(), MathFunctions.normalizeVector(currentPath.getClosestPointTangentVector())), 2) * curvature, -1, 1), currentPath.getClosestPointTangentVector().getTheta() + Math.PI / 2 * MathFunctions.getSign(currentPath.getClosestPointNormalVector().getTheta()));
|
||||
return centripetalVector;
|
||||
}
|
||||
|
||||
@ -1016,7 +996,7 @@ public class Follower {
|
||||
/**
|
||||
* This resets the IMU, if applicable.
|
||||
*/
|
||||
private void resetIMU() throws InterruptedException {
|
||||
public void resetIMU() {
|
||||
poseUpdater.resetIMU();
|
||||
}
|
||||
}
|
||||
|
@ -1,520 +0,0 @@
|
||||
|
||||
/* MIT License
|
||||
* Copyright (c) [2024] [Base 10 Assets, LLC]
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.firstinspires.ftc.teamcode.pedroPathing.localization;
|
||||
|
||||
import static com.qualcomm.robotcore.util.TypeConversion.byteArrayToInt;
|
||||
|
||||
import com.qualcomm.hardware.lynx.LynxI2cDeviceSynch;
|
||||
import com.qualcomm.robotcore.hardware.I2cAddr;
|
||||
import com.qualcomm.robotcore.hardware.I2cDeviceSynchDevice;
|
||||
import com.qualcomm.robotcore.hardware.I2cDeviceSynchSimple;
|
||||
import com.qualcomm.robotcore.hardware.configuration.annotations.DeviceProperties;
|
||||
import com.qualcomm.robotcore.hardware.configuration.annotations.I2cDeviceType;
|
||||
import com.qualcomm.robotcore.util.TypeConversion;
|
||||
|
||||
import org.firstinspires.ftc.robotcore.external.navigation.AngleUnit;
|
||||
import org.firstinspires.ftc.robotcore.external.navigation.DistanceUnit;
|
||||
import org.firstinspires.ftc.robotcore.external.navigation.Pose2D;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.Arrays;
|
||||
|
||||
|
||||
@I2cDeviceType
|
||||
@DeviceProperties(
|
||||
name = "goBILDA® Pinpoint Odometry Computer",
|
||||
xmlTag = "goBILDAPinpoint",
|
||||
description ="goBILDA® Pinpoint Odometry Computer (IMU Sensor Fusion for 2 Wheel Odometry)"
|
||||
)
|
||||
|
||||
public class GoBildaPinpointDriver extends I2cDeviceSynchDevice<I2cDeviceSynchSimple> {
|
||||
|
||||
private int deviceStatus = 0;
|
||||
private int loopTime = 0;
|
||||
private int xEncoderValue = 0;
|
||||
private int yEncoderValue = 0;
|
||||
private float xPosition = 0;
|
||||
private float yPosition = 0;
|
||||
private float hOrientation = 0;
|
||||
private float xVelocity = 0;
|
||||
private float yVelocity = 0;
|
||||
private float hVelocity = 0;
|
||||
|
||||
private static final float goBILDA_SWINGARM_POD = 13.26291192f; //ticks-per-mm for the goBILDA Swingarm Pod
|
||||
private static final float goBILDA_4_BAR_POD = 19.89436789f; //ticks-per-mm for the goBILDA 4-Bar Pod
|
||||
|
||||
//i2c address of the device
|
||||
public static final byte DEFAULT_ADDRESS = 0x31;
|
||||
|
||||
public GoBildaPinpointDriver(I2cDeviceSynchSimple deviceClient, boolean deviceClientIsOwned) {
|
||||
super(deviceClient, deviceClientIsOwned);
|
||||
|
||||
this.deviceClient.setI2cAddress(I2cAddr.create7bit(DEFAULT_ADDRESS));
|
||||
super.registerArmingStateCallback(false);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Manufacturer getManufacturer() {
|
||||
return Manufacturer.Other;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected synchronized boolean doInitialize() {
|
||||
((LynxI2cDeviceSynch)(deviceClient)).setBusSpeed(LynxI2cDeviceSynch.BusSpeed.FAST_400K);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDeviceName() {
|
||||
return "goBILDA® Pinpoint Odometry Computer";
|
||||
}
|
||||
|
||||
|
||||
//Register map of the i2c device
|
||||
private enum Register {
|
||||
DEVICE_ID (1),
|
||||
DEVICE_VERSION (2),
|
||||
DEVICE_STATUS (3),
|
||||
DEVICE_CONTROL (4),
|
||||
LOOP_TIME (5),
|
||||
X_ENCODER_VALUE (6),
|
||||
Y_ENCODER_VALUE (7),
|
||||
X_POSITION (8),
|
||||
Y_POSITION (9),
|
||||
H_ORIENTATION (10),
|
||||
X_VELOCITY (11),
|
||||
Y_VELOCITY (12),
|
||||
H_VELOCITY (13),
|
||||
MM_PER_TICK (14),
|
||||
X_POD_OFFSET (15),
|
||||
Y_POD_OFFSET (16),
|
||||
YAW_SCALAR (17),
|
||||
BULK_READ (18);
|
||||
|
||||
private final int bVal;
|
||||
|
||||
Register(int bVal){
|
||||
this.bVal = bVal;
|
||||
}
|
||||
}
|
||||
|
||||
//Device Status enum that captures the current fault condition of the device
|
||||
public enum DeviceStatus{
|
||||
NOT_READY (0),
|
||||
READY (1),
|
||||
CALIBRATING (1 << 1),
|
||||
FAULT_X_POD_NOT_DETECTED (1 << 2),
|
||||
FAULT_Y_POD_NOT_DETECTED (1 << 3),
|
||||
FAULT_NO_PODS_DETECTED (1 << 2 | 1 << 3),
|
||||
FAULT_IMU_RUNAWAY (1 << 4);
|
||||
|
||||
private final int status;
|
||||
|
||||
DeviceStatus(int status){
|
||||
this.status = status;
|
||||
}
|
||||
}
|
||||
|
||||
//enum that captures the direction the encoders are set to
|
||||
public enum EncoderDirection{
|
||||
FORWARD,
|
||||
REVERSED;
|
||||
}
|
||||
|
||||
//enum that captures the kind of goBILDA odometry pods, if goBILDA pods are used
|
||||
public enum GoBildaOdometryPods {
|
||||
goBILDA_SWINGARM_POD,
|
||||
goBILDA_4_BAR_POD;
|
||||
}
|
||||
//enum that captures a limited scope of read data. More options may be added in future update
|
||||
public enum readData {
|
||||
ONLY_UPDATE_HEADING,
|
||||
}
|
||||
|
||||
|
||||
/** Writes an int to the i2c device
|
||||
@param reg the register to write the int to
|
||||
@param i the integer to write to the register
|
||||
*/
|
||||
private void writeInt(final Register reg, int i){
|
||||
deviceClient.write(reg.bVal, TypeConversion.intToByteArray(i,ByteOrder.LITTLE_ENDIAN));
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads an int from a register of the i2c device
|
||||
* @param reg the register to read from
|
||||
* @return returns an int that contains the value stored in the read register
|
||||
*/
|
||||
private int readInt(Register reg){
|
||||
return byteArrayToInt(deviceClient.read(reg.bVal,4), ByteOrder.LITTLE_ENDIAN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a byte array to a float value
|
||||
* @param byteArray byte array to transform
|
||||
* @param byteOrder order of byte array to convert
|
||||
* @return the float value stored by the byte array
|
||||
*/
|
||||
private float byteArrayToFloat(byte[] byteArray, ByteOrder byteOrder){
|
||||
return ByteBuffer.wrap(byteArray).order(byteOrder).getFloat();
|
||||
}
|
||||
/**
|
||||
* Reads a float from a register
|
||||
* @param reg the register to read
|
||||
* @return the float value stored in that register
|
||||
*/
|
||||
|
||||
private float readFloat(Register reg){
|
||||
return byteArrayToFloat(deviceClient.read(reg.bVal,4),ByteOrder.LITTLE_ENDIAN);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Converts a float to a byte array
|
||||
* @param value the float array to convert
|
||||
* @return the byte array converted from the float
|
||||
*/
|
||||
private byte [] floatToByteArray (float value, ByteOrder byteOrder) {
|
||||
return ByteBuffer.allocate(4).order(byteOrder).putFloat(value).array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a byte array to a register on the i2c device
|
||||
* @param reg the register to write to
|
||||
* @param bytes the byte array to write
|
||||
*/
|
||||
private void writeByteArray (Register reg, byte[] bytes){
|
||||
deviceClient.write(reg.bVal,bytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a float to a register on the i2c device
|
||||
* @param reg the register to write to
|
||||
* @param f the float to write
|
||||
*/
|
||||
private void writeFloat (Register reg, float f){
|
||||
byte[] bytes = ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN).putFloat(f).array();
|
||||
deviceClient.write(reg.bVal,bytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks up the DeviceStatus enum corresponding with an int value
|
||||
* @param s int to lookup
|
||||
* @return the Odometry Computer state
|
||||
*/
|
||||
private DeviceStatus lookupStatus (int s){
|
||||
if ((s & DeviceStatus.CALIBRATING.status) != 0){
|
||||
return DeviceStatus.CALIBRATING;
|
||||
}
|
||||
boolean xPodDetected = (s & DeviceStatus.FAULT_X_POD_NOT_DETECTED.status) == 0;
|
||||
boolean yPodDetected = (s & DeviceStatus.FAULT_Y_POD_NOT_DETECTED.status) == 0;
|
||||
|
||||
if(!xPodDetected && !yPodDetected){
|
||||
return DeviceStatus.FAULT_NO_PODS_DETECTED;
|
||||
}
|
||||
if (!xPodDetected){
|
||||
return DeviceStatus.FAULT_X_POD_NOT_DETECTED;
|
||||
}
|
||||
if (!yPodDetected){
|
||||
return DeviceStatus.FAULT_Y_POD_NOT_DETECTED;
|
||||
}
|
||||
if ((s & DeviceStatus.FAULT_IMU_RUNAWAY.status) != 0){
|
||||
return DeviceStatus.FAULT_IMU_RUNAWAY;
|
||||
}
|
||||
if ((s & DeviceStatus.READY.status) != 0){
|
||||
return DeviceStatus.READY;
|
||||
}
|
||||
else {
|
||||
return DeviceStatus.NOT_READY;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this once per loop to read new data from the Odometry Computer. Data will only update once this is called.
|
||||
*/
|
||||
public void update(){
|
||||
byte[] bArr = deviceClient.read(Register.BULK_READ.bVal, 40);
|
||||
deviceStatus = byteArrayToInt(Arrays.copyOfRange (bArr, 0, 4), ByteOrder.LITTLE_ENDIAN);
|
||||
loopTime = byteArrayToInt(Arrays.copyOfRange (bArr, 4, 8), ByteOrder.LITTLE_ENDIAN);
|
||||
xEncoderValue = byteArrayToInt(Arrays.copyOfRange (bArr, 8, 12), ByteOrder.LITTLE_ENDIAN);
|
||||
yEncoderValue = byteArrayToInt(Arrays.copyOfRange (bArr, 12,16), ByteOrder.LITTLE_ENDIAN);
|
||||
xPosition = byteArrayToFloat(Arrays.copyOfRange(bArr, 16,20), ByteOrder.LITTLE_ENDIAN);
|
||||
yPosition = byteArrayToFloat(Arrays.copyOfRange(bArr, 20,24), ByteOrder.LITTLE_ENDIAN);
|
||||
hOrientation = byteArrayToFloat(Arrays.copyOfRange(bArr, 24,28), ByteOrder.LITTLE_ENDIAN);
|
||||
xVelocity = byteArrayToFloat(Arrays.copyOfRange(bArr, 28,32), ByteOrder.LITTLE_ENDIAN);
|
||||
yVelocity = byteArrayToFloat(Arrays.copyOfRange(bArr, 32,36), ByteOrder.LITTLE_ENDIAN);
|
||||
hVelocity = byteArrayToFloat(Arrays.copyOfRange(bArr, 36,40), ByteOrder.LITTLE_ENDIAN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this once per loop to read new data from the Odometry Computer. This is an override of the update() function
|
||||
* which allows a narrower range of data to be read from the device for faster read times. Currently ONLY_UPDATE_HEADING
|
||||
* is supported.
|
||||
* @param data GoBildaPinpointDriver.readData.ONLY_UPDATE_HEADING
|
||||
*/
|
||||
public void update(readData data) {
|
||||
if (data == readData.ONLY_UPDATE_HEADING) {
|
||||
hOrientation = byteArrayToFloat(deviceClient.read(Register.H_ORIENTATION.bVal, 4), ByteOrder.LITTLE_ENDIAN);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the odometry pod positions relative to the point that the odometry computer tracks around.<br><br>
|
||||
* The most common tracking position is the center of the robot. <br> <br>
|
||||
* The X pod offset refers to how far sideways (in mm) from the tracking point the X (forward) odometry pod is. Left of the center is a positive number, right of center is a negative number. <br>
|
||||
* the Y pod offset refers to how far forwards (in mm) from the tracking point the Y (strafe) odometry pod is. forward of center is a positive number, backwards is a negative number.<br>
|
||||
* @param xOffset how sideways from the center of the robot is the X (forward) pod? Left increases
|
||||
* @param yOffset how far forward from the center of the robot is the Y (Strafe) pod? forward increases
|
||||
*/
|
||||
public void setOffsets(double xOffset, double yOffset){
|
||||
writeFloat(Register.X_POD_OFFSET, (float) xOffset);
|
||||
writeFloat(Register.Y_POD_OFFSET, (float) yOffset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Recalibrates the Odometry Computer's internal IMU. <br><br>
|
||||
* <strong> Robot MUST be stationary </strong> <br><br>
|
||||
* Device takes a large number of samples, and uses those as the gyroscope zero-offset. This takes approximately 0.25 seconds.
|
||||
*/
|
||||
public void recalibrateIMU(){writeInt(Register.DEVICE_CONTROL,1<<0);}
|
||||
|
||||
/**
|
||||
* Resets the current position to 0,0,0 and recalibrates the Odometry Computer's internal IMU. <br><br>
|
||||
* <strong> Robot MUST be stationary </strong> <br><br>
|
||||
* Device takes a large number of samples, and uses those as the gyroscope zero-offset. This takes approximately 0.25 seconds.
|
||||
*/
|
||||
public void resetPosAndIMU(){writeInt(Register.DEVICE_CONTROL,1<<1);}
|
||||
|
||||
/**
|
||||
* Can reverse the direction of each encoder.
|
||||
* @param xEncoder FORWARD or REVERSED, X (forward) pod should increase when the robot is moving forward
|
||||
* @param yEncoder FORWARD or REVERSED, Y (strafe) pod should increase when the robot is moving left
|
||||
*/
|
||||
public void setEncoderDirections(EncoderDirection xEncoder, EncoderDirection yEncoder){
|
||||
if (xEncoder == EncoderDirection.FORWARD){
|
||||
writeInt(Register.DEVICE_CONTROL,1<<5);
|
||||
}
|
||||
if (xEncoder == EncoderDirection.REVERSED) {
|
||||
writeInt(Register.DEVICE_CONTROL,1<<4);
|
||||
}
|
||||
|
||||
if (yEncoder == EncoderDirection.FORWARD){
|
||||
writeInt(Register.DEVICE_CONTROL,1<<3);
|
||||
}
|
||||
if (yEncoder == EncoderDirection.REVERSED){
|
||||
writeInt(Register.DEVICE_CONTROL,1<<2);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If you're using goBILDA odometry pods, the ticks-per-mm values are stored here for easy access.<br><br>
|
||||
* @param pods goBILDA_SWINGARM_POD or goBILDA_4_BAR_POD
|
||||
*/
|
||||
public void setEncoderResolution(GoBildaOdometryPods pods){
|
||||
if (pods == GoBildaOdometryPods.goBILDA_SWINGARM_POD) {
|
||||
writeByteArray(Register.MM_PER_TICK, (floatToByteArray(goBILDA_SWINGARM_POD, ByteOrder.LITTLE_ENDIAN)));
|
||||
}
|
||||
if (pods == GoBildaOdometryPods.goBILDA_4_BAR_POD){
|
||||
writeByteArray(Register.MM_PER_TICK,(floatToByteArray(goBILDA_4_BAR_POD, ByteOrder.LITTLE_ENDIAN)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the encoder resolution in ticks per mm of the odometry pods. <br>
|
||||
* You can find this number by dividing the counts-per-revolution of your encoder by the circumference of the wheel.
|
||||
* @param ticks_per_mm should be somewhere between 10 ticks/mm and 100 ticks/mm a goBILDA Swingarm pod is ~13.26291192
|
||||
*/
|
||||
public void setEncoderResolution(double ticks_per_mm){
|
||||
writeByteArray(Register.MM_PER_TICK,(floatToByteArray((float) ticks_per_mm,ByteOrder.LITTLE_ENDIAN)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tuning this value should be unnecessary.<br>
|
||||
* The goBILDA Odometry Computer has a per-device tuned yaw offset already applied when you receive it.<br><br>
|
||||
* This is a scalar that is applied to the gyro's yaw value. Increasing it will mean it will report more than one degree for every degree the sensor fusion algorithm measures. <br><br>
|
||||
* You can tune this variable by rotating the robot a large amount (10 full turns is a good starting place) and comparing the amount that the robot rotated to the amount measured.
|
||||
* Rotating the robot exactly 10 times should measure 3600°. If it measures more or less, divide moved amount by the measured amount and apply that value to the Yaw Offset.<br><br>
|
||||
* If you find that to get an accurate heading number you need to apply a scalar of more than 1.05, or less than 0.95, your device may be bad. Please reach out to tech@gobilda.com
|
||||
* @param yawOffset A scalar for the robot's heading.
|
||||
*/
|
||||
public void setYawScalar(double yawOffset){
|
||||
writeByteArray(Register.YAW_SCALAR,(floatToByteArray((float) yawOffset, ByteOrder.LITTLE_ENDIAN)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a position that the Pinpoint should use to track your robot relative to. You can use this to
|
||||
* update the estimated position of your robot with new external sensor data, or to run a robot
|
||||
* in field coordinates. <br><br>
|
||||
* This overrides the current position. <br><br>
|
||||
* <strong>Using this feature to track your robot's position in field coordinates:</strong> <br>
|
||||
* When you start your code, send a Pose2D that describes the starting position on the field of your robot. <br>
|
||||
* Say you're on the red alliance, your robot is against the wall and closer to the audience side,
|
||||
* and the front of your robot is pointing towards the center of the field.
|
||||
* You can send a setPosition with something like -600mm x, -1200mm Y, and 90 degrees. The pinpoint would then always
|
||||
* keep track of how far away from the center of the field you are. <br><br>
|
||||
* <strong>Using this feature to update your position with additional sensors: </strong><br>
|
||||
* Some robots have a secondary way to locate their robot on the field. This is commonly
|
||||
* Apriltag localization in FTC, but it can also be something like a distance sensor.
|
||||
* Often these external sensors are absolute (meaning they measure something about the field)
|
||||
* so their data is very accurate. But they can be slower to read, or you may need to be in a very specific
|
||||
* position on the field to use them. In that case, spend most of your time relying on the Pinpoint
|
||||
* to determine your location. Then when you pull a new position from your secondary sensor,
|
||||
* send a setPosition command with the new position. The Pinpoint will then track your movement
|
||||
* relative to that new, more accurate position.
|
||||
* @param pos a Pose2D describing the robot's new position.
|
||||
*/
|
||||
public Pose2D setPosition(Pose2D pos){
|
||||
writeByteArray(Register.X_POSITION,(floatToByteArray((float) pos.getX(DistanceUnit.MM), ByteOrder.LITTLE_ENDIAN)));
|
||||
writeByteArray(Register.Y_POSITION,(floatToByteArray((float) pos.getY(DistanceUnit.MM),ByteOrder.LITTLE_ENDIAN)));
|
||||
writeByteArray(Register.H_ORIENTATION,(floatToByteArray((float) pos.getHeading(AngleUnit.RADIANS),ByteOrder.LITTLE_ENDIAN)));
|
||||
return pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the deviceID of the Odometry Computer. Should return 1.
|
||||
* @return 1 if device is functional.
|
||||
*/
|
||||
public int getDeviceID(){return readInt(Register.DEVICE_ID);}
|
||||
|
||||
/**
|
||||
* @return the firmware version of the Odometry Computer
|
||||
*/
|
||||
public int getDeviceVersion(){return readInt(Register.DEVICE_VERSION); }
|
||||
|
||||
public float getYawScalar(){return readFloat(Register.YAW_SCALAR); }
|
||||
|
||||
/**
|
||||
* Device Status stores any faults the Odometry Computer may be experiencing. These faults include:
|
||||
* @return one of the following states:<br>
|
||||
* NOT_READY - The device is currently powering up. And has not initialized yet. RED LED<br>
|
||||
* READY - The device is currently functioning as normal. GREEN LED<br>
|
||||
* CALIBRATING - The device is currently recalibrating the gyro. RED LED<br>
|
||||
* FAULT_NO_PODS_DETECTED - the device does not detect any pods plugged in. PURPLE LED <br>
|
||||
* FAULT_X_POD_NOT_DETECTED - The device does not detect an X pod plugged in. BLUE LED <br>
|
||||
* FAULT_Y_POD_NOT_DETECTED - The device does not detect a Y pod plugged in. ORANGE LED <br>
|
||||
*/
|
||||
public DeviceStatus getDeviceStatus(){return lookupStatus(deviceStatus); }
|
||||
|
||||
/**
|
||||
* Checks the Odometry Computer's most recent loop time.<br><br>
|
||||
* If values less than 500, or more than 1100 are commonly seen here, there may be something wrong with your device. Please reach out to tech@gobilda.com
|
||||
* @return loop time in microseconds (1/1,000,000 seconds)
|
||||
*/
|
||||
public int getLoopTime(){return loopTime; }
|
||||
|
||||
/**
|
||||
* Checks the Odometry Computer's most recent loop frequency.<br><br>
|
||||
* If values less than 900, or more than 2000 are commonly seen here, there may be something wrong with your device. Please reach out to tech@gobilda.com
|
||||
* @return Pinpoint Frequency in Hz (loops per second),
|
||||
*/
|
||||
public double getFrequency(){
|
||||
if (loopTime != 0){
|
||||
return 1000000.0/loopTime;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the raw value of the X (forward) encoder in ticks
|
||||
*/
|
||||
public int getEncoderX(){return xEncoderValue; }
|
||||
|
||||
/**
|
||||
* @return the raw value of the Y (strafe) encoder in ticks
|
||||
*/
|
||||
public int getEncoderY(){return yEncoderValue; }
|
||||
|
||||
/**
|
||||
* @return the estimated X (forward) position of the robot in mm
|
||||
*/
|
||||
public double getPosX(){return xPosition; }
|
||||
|
||||
/**
|
||||
* @return the estimated Y (Strafe) position of the robot in mm
|
||||
*/
|
||||
public double getPosY(){return yPosition; }
|
||||
|
||||
/**
|
||||
* @return the estimated H (heading) position of the robot in Radians
|
||||
*/
|
||||
public double getHeading(){return hOrientation;}
|
||||
|
||||
/**
|
||||
* @return the estimated X (forward) velocity of the robot in mm/sec
|
||||
*/
|
||||
public double getVelX(){return xVelocity; }
|
||||
|
||||
/**
|
||||
* @return the estimated Y (strafe) velocity of the robot in mm/sec
|
||||
*/
|
||||
public double getVelY(){return yVelocity; }
|
||||
|
||||
/**
|
||||
* @return the estimated H (heading) velocity of the robot in radians/sec
|
||||
*/
|
||||
public double getHeadingVelocity(){return hVelocity; }
|
||||
|
||||
/**
|
||||
* <strong> This uses its own I2C read, avoid calling this every loop. </strong>
|
||||
* @return the user-set offset for the X (forward) pod
|
||||
*/
|
||||
public float getXOffset(){return readFloat(Register.X_POD_OFFSET);}
|
||||
|
||||
/**
|
||||
* <strong> This uses its own I2C read, avoid calling this every loop. </strong>
|
||||
* @return the user-set offset for the Y (strafe) pod
|
||||
*/
|
||||
public float getYOffset(){return readFloat(Register.Y_POD_OFFSET);}
|
||||
|
||||
/**
|
||||
* @return a Pose2D containing the estimated position of the robot
|
||||
*/
|
||||
public Pose2D getPosition(){
|
||||
return new Pose2D(DistanceUnit.MM,
|
||||
xPosition,
|
||||
yPosition,
|
||||
AngleUnit.RADIANS,
|
||||
hOrientation);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return a Pose2D containing the estimated velocity of the robot, velocity is unit per second
|
||||
*/
|
||||
public Pose2D getVelocity(){
|
||||
return new Pose2D(DistanceUnit.MM,
|
||||
xVelocity,
|
||||
yVelocity,
|
||||
AngleUnit.RADIANS,
|
||||
hVelocity);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@ -1,7 +1,5 @@
|
||||
package org.firstinspires.ftc.teamcode.pedroPathing.localization;
|
||||
|
||||
import com.qualcomm.robotcore.hardware.IMU;
|
||||
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.pathGeneration.Vector;
|
||||
|
||||
/**
|
||||
@ -92,14 +90,5 @@ public abstract class Localizer {
|
||||
/**
|
||||
* This resets the IMU of the localizer, if applicable.
|
||||
*/
|
||||
public abstract void resetIMU() throws InterruptedException;
|
||||
|
||||
/**
|
||||
* This is overridden to return the IMU, if there is one.
|
||||
*
|
||||
* @return returns the IMU if it exists
|
||||
*/
|
||||
public IMU getIMU() {
|
||||
return null;
|
||||
}
|
||||
public abstract void resetIMU();
|
||||
}
|
||||
|
@ -1,7 +1,5 @@
|
||||
package org.firstinspires.ftc.teamcode.pedroPathing.localization;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.pathGeneration.MathFunctions;
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.pathGeneration.Vector;
|
||||
|
||||
@ -46,7 +44,7 @@ public class Pose {
|
||||
* This creates a new Pose with no inputs and 0 for all values.
|
||||
*/
|
||||
public Pose() {
|
||||
this(0, 0, 0);
|
||||
this(0,0,0);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -210,10 +208,4 @@ public class Pose {
|
||||
public Pose copy() {
|
||||
return new Pose(getX(), getY(), getHeading());
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
return "(" + getX() + ", " + getY() + ", " + Math.toDegrees(getHeading()) + ")";
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import com.qualcomm.robotcore.hardware.HardwareMap;
|
||||
import com.qualcomm.robotcore.hardware.IMU;
|
||||
|
||||
import org.firstinspires.ftc.robotcore.external.navigation.AngleUnit;
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.localization.localizers.DriveEncoderLocalizer;
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.localization.localizers.ThreeWheelIMULocalizer;
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.localization.localizers.ThreeWheelLocalizer;
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.localization.localizers.TwoWheelLocalizer;
|
||||
@ -60,7 +61,6 @@ public class PoseUpdater {
|
||||
}
|
||||
|
||||
this.localizer = localizer;
|
||||
imu = localizer.getIMU();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -71,6 +71,7 @@ public class PoseUpdater {
|
||||
public PoseUpdater(HardwareMap hardwareMap) {
|
||||
// TODO: replace the second argument with your preferred localizer
|
||||
this(hardwareMap, new ThreeWheelLocalizer(hardwareMap));
|
||||
// this(hardwareMap, new ThreeWheelIMULocalizer(hardwareMap));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -262,10 +263,9 @@ public class PoseUpdater {
|
||||
*/
|
||||
public Vector getVelocity() {
|
||||
if (currentVelocity == null) {
|
||||
// currentVelocity = new Vector();
|
||||
// currentVelocity.setOrthogonalComponents(getPose().getX() - previousPose.getX(), getPose().getY() - previousPose.getY());
|
||||
// currentVelocity.setMagnitude(MathFunctions.distance(getPose(), previousPose) / ((currentPoseTime - previousPoseTime) / Math.pow(10.0, 9)));
|
||||
currentVelocity = localizer.getVelocityVector();
|
||||
currentVelocity = new Vector();
|
||||
currentVelocity.setOrthogonalComponents(getPose().getX() - previousPose.getX(), getPose().getY() - previousPose.getY());
|
||||
currentVelocity.setMagnitude(MathFunctions.distance(getPose(), previousPose) / ((currentPoseTime - previousPoseTime) / Math.pow(10.0, 9)));
|
||||
return MathFunctions.copyVector(currentVelocity);
|
||||
} else {
|
||||
return MathFunctions.copyVector(currentVelocity);
|
||||
@ -302,9 +302,7 @@ public class PoseUpdater {
|
||||
* This resets the heading of the robot to the IMU's heading, using Road Runner's pose reset.
|
||||
*/
|
||||
public void resetHeadingToIMU() {
|
||||
if (imu != null) {
|
||||
localizer.setPose(new Pose(getPose().getX(), getPose().getY(), getNormalizedIMUHeading() + startingPose.getHeading()));
|
||||
}
|
||||
localizer.setPose(new Pose(getPose().getX(), getPose().getY(), getNormalizedIMUHeading() + startingPose.getHeading()));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -313,9 +311,7 @@ public class PoseUpdater {
|
||||
* method.
|
||||
*/
|
||||
public void resetHeadingToIMUWithOffsets() {
|
||||
if (imu != null) {
|
||||
setCurrentPoseWithOffset(new Pose(getPose().getX(), getPose().getY(), getNormalizedIMUHeading() + startingPose.getHeading()));
|
||||
}
|
||||
setCurrentPoseWithOffset(new Pose(getPose().getX(), getPose().getY(), getNormalizedIMUHeading() + startingPose.getHeading()));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -324,10 +320,7 @@ public class PoseUpdater {
|
||||
* @return returns the normalized IMU heading.
|
||||
*/
|
||||
public double getNormalizedIMUHeading() {
|
||||
if (imu != null) {
|
||||
return MathFunctions.normalizeAngle(-imu.getRobotYawPitchRollAngles().getYaw(AngleUnit.RADIANS));
|
||||
}
|
||||
return 0;
|
||||
return MathFunctions.normalizeAngle(-imu.getRobotYawPitchRollAngles().getYaw(AngleUnit.RADIANS));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -351,7 +344,7 @@ public class PoseUpdater {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public void resetIMU() throws InterruptedException {
|
||||
public void resetIMU() {
|
||||
localizer.resetIMU();
|
||||
}
|
||||
}
|
||||
|
@ -38,9 +38,9 @@ public class DriveEncoderLocalizer extends Localizer {
|
||||
private Encoder leftRear;
|
||||
private Encoder rightRear;
|
||||
private double totalHeading;
|
||||
public static double FORWARD_TICKS_TO_INCHES = 1;
|
||||
public static double STRAFE_TICKS_TO_INCHES = 1;
|
||||
public static double TURN_TICKS_TO_RADIANS = 1;
|
||||
public static double FORWARD_TICKS_TO_INCHES = -0.6308;
|
||||
public static double STRAFE_TICKS_TO_INCHES = 46.4839;
|
||||
public static double TURN_TICKS_TO_RADIANS = -0.002;
|
||||
public static double ROBOT_WIDTH = 1;
|
||||
public static double ROBOT_LENGTH = 1;
|
||||
|
||||
@ -71,8 +71,8 @@ public class DriveEncoderLocalizer extends Localizer {
|
||||
|
||||
// TODO: reverse any encoders necessary
|
||||
leftFront.setDirection(Encoder.REVERSE);
|
||||
leftRear.setDirection(Encoder.REVERSE);
|
||||
rightFront.setDirection(Encoder.FORWARD);
|
||||
rightRear.setDirection(Encoder.REVERSE);
|
||||
leftRear.setDirection(Encoder.FORWARD);
|
||||
rightRear.setDirection(Encoder.FORWARD);
|
||||
|
||||
setStartPose(setStartPose);
|
||||
@ -182,7 +182,7 @@ public class DriveEncoderLocalizer extends Localizer {
|
||||
globalDeltas = Matrix.multiply(Matrix.multiply(prevRotationMatrix, transformation), robotDeltas);
|
||||
|
||||
displacementPose.add(new Pose(globalDeltas.get(0, 0), globalDeltas.get(1, 0), globalDeltas.get(2, 0)));
|
||||
currentVelocity = new Pose(globalDeltas.get(0, 0) / (deltaTimeNano / Math.pow(10.0, 9)), globalDeltas.get(1, 0) / (deltaTimeNano / Math.pow(10.0, 9)), globalDeltas.get(2, 0) / (deltaTimeNano / Math.pow(10.0, 9)));
|
||||
currentVelocity = new Pose(globalDeltas.get(0, 0) / (deltaTimeNano * Math.pow(10.0, 9)), globalDeltas.get(1, 0) / (deltaTimeNano * Math.pow(10.0, 9)), globalDeltas.get(2, 0) / (deltaTimeNano * Math.pow(10.0, 9)));
|
||||
|
||||
totalHeading += globalDeltas.get(2, 0);
|
||||
}
|
||||
|
@ -21,18 +21,18 @@ import org.firstinspires.ftc.teamcode.pedroPathing.pathGeneration.Vector;
|
||||
*
|
||||
* forward on robot is the x positive direction
|
||||
*
|
||||
* forward (x positive)
|
||||
* △
|
||||
* |
|
||||
* |
|
||||
* /--------------\
|
||||
* | |
|
||||
* | |
|
||||
* | || || |
|
||||
* left (y positive) <--- | || || |
|
||||
* | ____ |
|
||||
* | ---- |
|
||||
* \--------------/
|
||||
* /--------------\
|
||||
* | ____ |
|
||||
* | ---- |
|
||||
* | || || |
|
||||
* | || || | ----> left (y positive)
|
||||
* | |
|
||||
* | |
|
||||
* \--------------/
|
||||
* |
|
||||
* |
|
||||
* V
|
||||
* forward (x positive)
|
||||
*
|
||||
* @author Anyi Lin - 10158 Scott's Bots
|
||||
* @version 1.0, 7/20/2024
|
||||
@ -41,9 +41,6 @@ public class OTOSLocalizer extends Localizer {
|
||||
private HardwareMap hardwareMap;
|
||||
private Pose startPose;
|
||||
private SparkFunOTOS otos;
|
||||
private SparkFunOTOS.Pose2D otosPose;
|
||||
private SparkFunOTOS.Pose2D otosVel;
|
||||
private SparkFunOTOS.Pose2D otosAcc;
|
||||
private double previousHeading;
|
||||
private double totalHeading;
|
||||
|
||||
@ -67,12 +64,13 @@ public class OTOSLocalizer extends Localizer {
|
||||
public OTOSLocalizer(HardwareMap map, Pose setStartPose) {
|
||||
hardwareMap = map;
|
||||
|
||||
// TODO: replace this with your OTOS port
|
||||
/*
|
||||
TODO: If you want to use the "SparkFunOTOSCorrected" version of OTOS, then replace the
|
||||
'SparkFunOTOS.class' below with 'SparkFunOTOSCorrected.class' and set the OTOS as a
|
||||
"SparkFunOTOS Corrected" in your robot config
|
||||
"SparkFunOTOS Corrected" in your robot confg
|
||||
*/
|
||||
// TODO: replace this with your OTOS port
|
||||
SparkFunOTOS
|
||||
otos = hardwareMap.get(SparkFunOTOS.class, "sensor_otos");
|
||||
|
||||
otos.setLinearUnit(DistanceUnit.INCH);
|
||||
@ -92,9 +90,6 @@ public class OTOSLocalizer extends Localizer {
|
||||
otos.resetTracking();
|
||||
|
||||
setStartPose(setStartPose);
|
||||
otosPose = new SparkFunOTOS.Pose2D();
|
||||
otosVel = new SparkFunOTOS.Pose2D();
|
||||
otosAcc = new SparkFunOTOS.Pose2D();
|
||||
totalHeading = 0;
|
||||
previousHeading = startPose.getHeading();
|
||||
|
||||
@ -108,12 +103,8 @@ public class OTOSLocalizer extends Localizer {
|
||||
*/
|
||||
@Override
|
||||
public Pose getPose() {
|
||||
Pose pose = new Pose(otosPose.x, otosPose.y, otosPose.h);
|
||||
|
||||
Vector vec = pose.getVector();
|
||||
vec.rotateVector(startPose.getHeading());
|
||||
|
||||
return MathFunctions.addPoses(startPose, new Pose(vec.getXComponent(), vec.getYComponent(), pose.getHeading()));
|
||||
SparkFunOTOS.Pose2D pose = otos.getPosition();
|
||||
return MathFunctions.addPoses(startPose, new Pose(pose.x, pose.y, pose.h));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -123,7 +114,8 @@ public class OTOSLocalizer extends Localizer {
|
||||
*/
|
||||
@Override
|
||||
public Pose getVelocity() {
|
||||
return new Pose(otosVel.x, otosVel.y, otosVel.h);
|
||||
SparkFunOTOS.Pose2D OTOSVelocity = otos.getVelocity();
|
||||
return new Pose(OTOSVelocity.x, OTOSVelocity.y, OTOSVelocity.h);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -165,9 +157,8 @@ public class OTOSLocalizer extends Localizer {
|
||||
*/
|
||||
@Override
|
||||
public void update() {
|
||||
otos.getPosVelAcc(otosPose,otosVel,otosAcc);
|
||||
totalHeading += MathFunctions.getSmallestAngleDifference(otosPose.h, previousHeading);
|
||||
previousHeading = otosPose.h;
|
||||
totalHeading += MathFunctions.getSmallestAngleDifference(otos.getPosition().h, previousHeading);
|
||||
previousHeading = otos.getPosition().h;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,245 +0,0 @@
|
||||
package org.firstinspires.ftc.teamcode.pedroPathing.localization.localizers;
|
||||
|
||||
|
||||
import com.qualcomm.robotcore.hardware.HardwareMap;
|
||||
|
||||
import org.firstinspires.ftc.robotcore.external.navigation.AngleUnit;
|
||||
import org.firstinspires.ftc.robotcore.external.navigation.DistanceUnit;
|
||||
import org.firstinspires.ftc.robotcore.external.navigation.Pose2D;
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.localization.GoBildaPinpointDriver;
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.localization.Localizer;
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.localization.Pose;
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.pathGeneration.MathFunctions;
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.pathGeneration.Vector;
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.util.NanoTimer;
|
||||
import org.opencv.core.Mat;
|
||||
|
||||
/**
|
||||
* This is the Pinpoint class. This class extends the Localizer superclass and is a
|
||||
* localizer that uses the two wheel odometry set up with the IMU to have more accurate heading
|
||||
* readings. The diagram below, which is modified from Road Runner, shows a typical set up.
|
||||
*
|
||||
* The view is from the top of the robot looking downwards.
|
||||
*
|
||||
* left on robot is the y positive direction
|
||||
*
|
||||
* forward on robot is the x positive direction
|
||||
*
|
||||
* /--------------\
|
||||
* | ____ |
|
||||
* | ---- |
|
||||
* | || |
|
||||
* | || | ----> left (y positive)
|
||||
* | |
|
||||
* | |
|
||||
* \--------------/
|
||||
* |
|
||||
* |
|
||||
* V
|
||||
* forward (x positive)
|
||||
* With the pinpoint your readings will be used in mm
|
||||
* to use inches ensure to divide your mm value by 25.4
|
||||
* @author Logan Nash
|
||||
* @author Havish Sripada 12808 - RevAmped Robotics
|
||||
* @author Ethan Doak - Gobilda
|
||||
* @version 1.0, 10/2/2024
|
||||
*/
|
||||
public class PinpointLocalizer extends Localizer {
|
||||
private HardwareMap hardwareMap;
|
||||
private GoBildaPinpointDriver odo;
|
||||
private double previousHeading;
|
||||
private double totalHeading;
|
||||
private Pose startPose;
|
||||
private long deltaTimeNano;
|
||||
private NanoTimer timer;
|
||||
private Pose currentVelocity;
|
||||
private Pose previousPinpointPose;
|
||||
|
||||
/**
|
||||
* This creates a new PinpointLocalizer from a HardwareMap, with a starting Pose at (0,0)
|
||||
* facing 0 heading.
|
||||
*
|
||||
* @param map the HardwareMap
|
||||
*/
|
||||
public PinpointLocalizer(HardwareMap map){ this(map, new Pose());}
|
||||
|
||||
/**
|
||||
* This creates a new PinpointLocalizer from a HardwareMap and a Pose, with the Pose
|
||||
* specifying the starting pose of the localizer.
|
||||
*
|
||||
* @param map the HardwareMap
|
||||
* @param setStartPose the Pose to start from
|
||||
*/
|
||||
public PinpointLocalizer(HardwareMap map, Pose setStartPose){
|
||||
hardwareMap = map;
|
||||
|
||||
odo = hardwareMap.get(GoBildaPinpointDriver.class,"pinpoint");
|
||||
|
||||
//The default units are inches, but you can swap the units if you wish.
|
||||
//If you have already tuned the TwoWheelLocalizer, you can simply use the forwardEncoderPose's y value and strafeEncoderPose's x values.
|
||||
setOffsets(-2.815, 0.125, DistanceUnit.INCH); //these are tuned for 3110-0002-0001 Product Insight #1
|
||||
|
||||
//TODO: Tune urself if needed
|
||||
// odo.setYawScalar(1.0);
|
||||
|
||||
odo.setEncoderResolution(GoBildaPinpointDriver.GoBildaOdometryPods.goBILDA_4_BAR_POD);
|
||||
//odo.setEncoderResolution(13.26291192);
|
||||
|
||||
odo.setEncoderDirections(GoBildaPinpointDriver.EncoderDirection.REVERSED, GoBildaPinpointDriver.EncoderDirection.FORWARD);
|
||||
|
||||
resetPinpoint();
|
||||
|
||||
setStartPose(setStartPose);
|
||||
totalHeading = 0;
|
||||
timer = new NanoTimer();
|
||||
previousPinpointPose = new Pose();
|
||||
currentVelocity = new Pose();
|
||||
deltaTimeNano = 1;
|
||||
previousHeading = setStartPose.getHeading();
|
||||
}
|
||||
|
||||
/**
|
||||
* This returns the current pose estimate.
|
||||
*
|
||||
* @return returns the current pose estimate as a Pose
|
||||
*/
|
||||
@Override
|
||||
public Pose getPose() {
|
||||
return MathFunctions.addPoses(startPose, MathFunctions.rotatePose(previousPinpointPose, startPose.getHeading(), false));
|
||||
}
|
||||
|
||||
/**
|
||||
* This returns the current velocity estimate.
|
||||
*
|
||||
* @return returns the current velocity estimate as a Pose
|
||||
*/
|
||||
@Override
|
||||
public Pose getVelocity() {
|
||||
return currentVelocity.copy();
|
||||
}
|
||||
|
||||
/**
|
||||
* This returns the current velocity estimate.
|
||||
*
|
||||
* @return returns the current velocity estimate as a Vector
|
||||
*/
|
||||
@Override
|
||||
public Vector getVelocityVector() {
|
||||
return currentVelocity.getVector();
|
||||
}
|
||||
|
||||
/**
|
||||
* This sets the start pose. Since nobody should be using this after the robot has begun moving,
|
||||
* and due to issues with the PinpointLocalizer, this is functionally the same as setPose(Pose).
|
||||
*
|
||||
* @param setStart the new start pose
|
||||
*/
|
||||
@Override
|
||||
public void setStartPose(Pose setStart) {
|
||||
this.startPose = setStart;
|
||||
}
|
||||
|
||||
/**
|
||||
* This sets the current pose estimate. Changing this should just change the robot's current
|
||||
* pose estimate, not anything to do with the start pose.
|
||||
*
|
||||
* @param setPose the new current pose estimate
|
||||
*/
|
||||
@Override
|
||||
public void setPose(Pose setPose) {
|
||||
Pose setNewPose = MathFunctions.subtractPoses(setPose, startPose);
|
||||
odo.setPosition(new Pose2D(DistanceUnit.INCH, setNewPose.getX(), setNewPose.getY(), AngleUnit.RADIANS, setNewPose.getHeading()));
|
||||
}
|
||||
|
||||
/**
|
||||
* This updates the total heading of the robot. The Pinpoint handles all other updates itself.
|
||||
*/
|
||||
@Override
|
||||
public void update() {
|
||||
deltaTimeNano = timer.getElapsedTime();
|
||||
timer.resetTimer();
|
||||
odo.update();
|
||||
Pose2D pinpointPose = odo.getPosition();
|
||||
Pose currentPinpointPose = new Pose(pinpointPose.getX(DistanceUnit.INCH), pinpointPose.getY(DistanceUnit.INCH), pinpointPose.getHeading(AngleUnit.RADIANS));
|
||||
totalHeading += MathFunctions.getSmallestAngleDifference(currentPinpointPose.getHeading(), previousHeading);
|
||||
previousHeading = currentPinpointPose.getHeading();
|
||||
Pose deltaPose = MathFunctions.subtractPoses(currentPinpointPose, previousPinpointPose);
|
||||
currentVelocity = new Pose(deltaPose.getX() / (deltaTimeNano / Math.pow(10.0, 9)), deltaPose.getY() / (deltaTimeNano / Math.pow(10.0, 9)), deltaPose.getHeading() / (deltaTimeNano / Math.pow(10.0, 9)));
|
||||
previousPinpointPose = currentPinpointPose;
|
||||
}
|
||||
|
||||
/**
|
||||
* This returns how far the robot has turned in radians, in a number not clamped between 0 and
|
||||
* 2 * pi radians. This is used for some tuning things and nothing actually within the following.
|
||||
*
|
||||
* @return returns how far the robot has turned in total, in radians.
|
||||
*/
|
||||
@Override
|
||||
public double getTotalHeading() {
|
||||
return totalHeading;
|
||||
}
|
||||
|
||||
/**
|
||||
* This returns the Y encoder value as none of the odometry tuners are required for this localizer
|
||||
* @return returns the Y encoder value
|
||||
*/
|
||||
@Override
|
||||
public double getForwardMultiplier() {
|
||||
return odo.getEncoderY();
|
||||
}
|
||||
|
||||
/**
|
||||
* This returns the X encoder value as none of the odometry tuners are required for this localizer
|
||||
* @return returns the X encoder value
|
||||
*/
|
||||
@Override
|
||||
public double getLateralMultiplier() {
|
||||
return odo.getEncoderX();
|
||||
}
|
||||
|
||||
/**
|
||||
* This returns either the factory tuned yaw scalar or the yaw scalar tuned by yourself.
|
||||
* @return returns the yaw scalar
|
||||
*/
|
||||
@Override
|
||||
public double getTurningMultiplier() {
|
||||
return odo.getYawScalar();
|
||||
}
|
||||
|
||||
/**
|
||||
* This sets the offsets and converts inches to millimeters
|
||||
* @param xOffset How far to the side from the center of the robot is the x-pod? Use positive values if it's to the left and negative if it's to the right.
|
||||
* @param yOffset How far forward from the center of the robot is the y-pod? Use positive values if it's forward and negative if it's to the back.
|
||||
* @param unit The units that the measurements are given in
|
||||
*/
|
||||
private void setOffsets(double xOffset, double yOffset, DistanceUnit unit) {
|
||||
odo.setOffsets(unit.toMm(xOffset), unit.toMm(yOffset));
|
||||
}
|
||||
|
||||
/**
|
||||
* This resets the IMU. Does not change heading estimation.
|
||||
*/
|
||||
@Override
|
||||
public void resetIMU() throws InterruptedException {
|
||||
odo.recalibrateIMU();
|
||||
|
||||
try {
|
||||
Thread.sleep(300);
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This resets the pinpoint.
|
||||
*/
|
||||
private void resetPinpoint() {
|
||||
odo.resetPosAndIMU();
|
||||
|
||||
try {
|
||||
Thread.sleep(300);
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,7 @@
|
||||
package org.firstinspires.ftc.teamcode.pedroPathing.localization.localizers;
|
||||
|
||||
import static org.firstinspires.ftc.teamcode.PedroConstants.*;
|
||||
|
||||
import com.acmerobotics.dashboard.config.Config;
|
||||
import com.qualcomm.hardware.rev.RevHubOrientationOnRobot;
|
||||
import com.qualcomm.robotcore.hardware.DcMotorEx;
|
||||
@ -26,18 +28,18 @@ import org.firstinspires.ftc.teamcode.pedroPathing.util.NanoTimer;
|
||||
*
|
||||
* forward on robot is the x positive direction
|
||||
*
|
||||
* forward (x positive)
|
||||
* △
|
||||
* |
|
||||
* |
|
||||
* /--------------\
|
||||
* | |
|
||||
* | |
|
||||
* | || || |
|
||||
* left (y positive) <--- | || || |
|
||||
* | ____ |
|
||||
* | ---- |
|
||||
* \--------------/
|
||||
* /--------------\
|
||||
* | ____ |
|
||||
* | ---- |
|
||||
* | || || |
|
||||
* | || || | ----> left (y positive)
|
||||
* | |
|
||||
* | |
|
||||
* \--------------/
|
||||
* |
|
||||
* |
|
||||
* V
|
||||
* forward (x positive)
|
||||
*
|
||||
* @author Logan Nash
|
||||
* @author Anyi Lin - 10158 Scott's Bots
|
||||
@ -63,9 +65,9 @@ public class ThreeWheelIMULocalizer extends Localizer {
|
||||
private double previousIMUOrientation;
|
||||
private double deltaRadians;
|
||||
private double totalHeading;
|
||||
public static double FORWARD_TICKS_TO_INCHES = 0.002957;//8192 * 1.37795 * 2 * Math.PI * 0.5008239963;
|
||||
public static double STRAFE_TICKS_TO_INCHES = -0.003127403096038503;//8192 * 1.37795 * 2 * Math.PI * 0.5018874659;
|
||||
public static double TURN_TICKS_TO_RADIANS = 0.002995;//8192 * 1.37795 * 2 * Math.PI * 0.5;
|
||||
public static double FORWARD_TICKS_TO_INCHES = 0.004;//8192 * 1.37795 * 2 * Math.PI * 0.5008239963;
|
||||
public static double STRAFE_TICKS_TO_INCHES = -0.0036;//8192 * 1.37795 * 2 * Math.PI * 0.5018874659;
|
||||
public static double TURN_TICKS_TO_RADIANS = 0.0043;//8192 * 1.37795 * 2 * Math.PI * 0.5;
|
||||
|
||||
public static boolean useIMU = true;
|
||||
|
||||
@ -88,26 +90,25 @@ public class ThreeWheelIMULocalizer extends Localizer {
|
||||
*/
|
||||
public ThreeWheelIMULocalizer(HardwareMap map, Pose setStartPose) {
|
||||
hardwareMap = map;
|
||||
imu = hardwareMap.get(IMU.class, "imu");
|
||||
imu = hardwareMap.get(IMU.class, IMU);
|
||||
|
||||
// TODO: replace this with your IMU's orientation
|
||||
imu.initialize(new IMU.Parameters(new RevHubOrientationOnRobot(RevHubOrientationOnRobot.LogoFacingDirection.LEFT, RevHubOrientationOnRobot.UsbFacingDirection.UP)));
|
||||
imu.initialize(new IMU.Parameters(new RevHubOrientationOnRobot(IMU_LOGO_FACING_DIRECTION, IMU_USB_FACING_DIRECTION)));
|
||||
|
||||
// TODO: replace these with your encoder positions
|
||||
leftEncoderPose = new Pose(-3, 5.7, 0);
|
||||
rightEncoderPose = new Pose(-3, -5.7, 0);
|
||||
strafeEncoderPose = new Pose(6.9, 1, Math.toRadians(90));
|
||||
|
||||
leftEncoderPose = new Pose(-7.625, 6.19375, 0);
|
||||
rightEncoderPose = new Pose(-7.625, -6.19375, 0);
|
||||
strafeEncoderPose = new Pose(7, 1, Math.toRadians(90));
|
||||
|
||||
// TODO: replace these with your encoder ports
|
||||
leftEncoder = new Encoder(hardwareMap.get(DcMotorEx.class, "lb"));
|
||||
rightEncoder = new Encoder(hardwareMap.get(DcMotorEx.class, "lf"));
|
||||
strafeEncoder = new Encoder(hardwareMap.get(DcMotorEx.class, "rf"));
|
||||
leftEncoder = new Encoder(hardwareMap.get(DcMotorEx.class, LEFT_ENCODER));
|
||||
rightEncoder = new Encoder(hardwareMap.get(DcMotorEx.class, RIGHT_ENCODER));
|
||||
strafeEncoder = new Encoder(hardwareMap.get(DcMotorEx.class, BACK_ENCODER));
|
||||
|
||||
// TODO: reverse any encoders necessary
|
||||
leftEncoder.setDirection(Encoder.REVERSE);
|
||||
rightEncoder.setDirection(Encoder.FORWARD);
|
||||
strafeEncoder.setDirection(Encoder.FORWARD);
|
||||
leftEncoder.setDirection(LEFT_ENCODER_DIRECTION);
|
||||
rightEncoder.setDirection(RIGHT_ENCODER_DIRECTION);
|
||||
strafeEncoder.setDirection(BACK_ENCODER_DIRECTION);
|
||||
|
||||
setStartPose(setStartPose);
|
||||
timer = new NanoTimer();
|
||||
@ -219,7 +220,7 @@ public class ThreeWheelIMULocalizer extends Localizer {
|
||||
globalDeltas = Matrix.multiply(Matrix.multiply(prevRotationMatrix, transformation), robotDeltas);
|
||||
|
||||
displacementPose.add(new Pose(globalDeltas.get(0, 0), globalDeltas.get(1, 0), globalDeltas.get(2, 0)));
|
||||
currentVelocity = new Pose(globalDeltas.get(0, 0) / (deltaTimeNano / Math.pow(10.0, 9)), globalDeltas.get(1, 0) / (deltaTimeNano / Math.pow(10.0, 9)), globalDeltas.get(2, 0) / (deltaTimeNano / Math.pow(10.0, 9)));
|
||||
currentVelocity = new Pose(globalDeltas.get(0, 0) / (deltaTimeNano * Math.pow(10.0, 9)), globalDeltas.get(1, 0) / (deltaTimeNano * Math.pow(10.0, 9)), globalDeltas.get(2, 0) / (deltaTimeNano * Math.pow(10.0, 9)));
|
||||
|
||||
totalHeading += globalDeltas.get(2, 0);
|
||||
}
|
||||
@ -313,14 +314,4 @@ public class ThreeWheelIMULocalizer extends Localizer {
|
||||
public void resetIMU() {
|
||||
imu.resetYaw();
|
||||
}
|
||||
|
||||
/**
|
||||
* This is returns the IMU.
|
||||
*
|
||||
* @return returns the IMU
|
||||
*/
|
||||
@Override
|
||||
public IMU getIMU() {
|
||||
return imu;
|
||||
}
|
||||
}
|
@ -25,18 +25,18 @@ import org.firstinspires.ftc.teamcode.pedroPathing.util.NanoTimer;
|
||||
*
|
||||
* forward on robot is the x positive direction
|
||||
*
|
||||
* forward (x positive)
|
||||
* △
|
||||
* |
|
||||
* |
|
||||
* /--------------\
|
||||
* | |
|
||||
* | |
|
||||
* | || || |
|
||||
* left (y positive) <--- | || || |
|
||||
* | ____ |
|
||||
* | ---- |
|
||||
* \--------------/
|
||||
* /--------------\
|
||||
* | ____ |
|
||||
* | ---- |
|
||||
* | || || |
|
||||
* | || || | ----> left (y positive)
|
||||
* | |
|
||||
* | |
|
||||
* \--------------/
|
||||
* |
|
||||
* |
|
||||
* V
|
||||
* forward (x positive)
|
||||
*
|
||||
* @author Anyi Lin - 10158 Scott's Bots
|
||||
* @version 1.0, 4/2/2024
|
||||
@ -57,9 +57,12 @@ public class ThreeWheelLocalizer extends Localizer {
|
||||
private Pose rightEncoderPose;
|
||||
private Pose strafeEncoderPose;
|
||||
private double totalHeading;
|
||||
public static double FORWARD_TICKS_TO_INCHES = 0.003;//8192 * 1.37795 * 2 * Math.PI * 0.5008239963;
|
||||
public static double STRAFE_TICKS_TO_INCHES = -0.003;//8192 * 1.37795 * 2 * Math.PI * 0.5018874659;
|
||||
public static double TURN_TICKS_TO_RADIANS = 0.0029;//8192 * 1.37795 * 2 * Math.PI * 0.5;
|
||||
// public static double FORWARD_TICKS_TO_INCHES = 0.00052189;//8192 * 1.37795 * 2 * Math.PI * 0.5008239963;
|
||||
public static double FORWARD_TICKS_TO_INCHES = 0.0029;//8192 * 1.37795 * 2 * Math.PI * 0.5008239963;
|
||||
// public static double STRAFE_TICKS_TO_INCHES = 0.00052189;//8192 * 1.37795 * 2 * Math.PI * 0.5018874659;
|
||||
public static double STRAFE_TICKS_TO_INCHES = 0.0029;//8192 * 1.37795 * 2 * Math.PI * 0.5018874659;
|
||||
// public static double TURN_TICKS_TO_RADIANS = 0.00053717;//8192 * 1.37795 * 2 * Math.PI * 0.5;
|
||||
public static double TURN_TICKS_TO_RADIANS = 0.003;//8192 * 1.37795 * 2 * Math.PI * 0.5;
|
||||
|
||||
/**
|
||||
* This creates a new ThreeWheelLocalizer from a HardwareMap, with a starting Pose at (0,0)
|
||||
@ -80,9 +83,9 @@ public class ThreeWheelLocalizer extends Localizer {
|
||||
*/
|
||||
public ThreeWheelLocalizer(HardwareMap map, Pose setStartPose) {
|
||||
// TODO: replace these with your encoder positions
|
||||
leftEncoderPose = new Pose(0.25, 6.25, 0);
|
||||
rightEncoderPose = new Pose(0.25, -6.25, 0);
|
||||
strafeEncoderPose = new Pose(-7, 0.25, Math.toRadians(90));
|
||||
leftEncoderPose = new Pose(0, 6.19375, 0);
|
||||
rightEncoderPose = new Pose(0, -6.19375, 0);
|
||||
strafeEncoderPose = new Pose(-7, 0, Math.toRadians(90));
|
||||
|
||||
hardwareMap = map;
|
||||
|
||||
@ -206,7 +209,7 @@ public class ThreeWheelLocalizer extends Localizer {
|
||||
globalDeltas = Matrix.multiply(Matrix.multiply(prevRotationMatrix, transformation), robotDeltas);
|
||||
|
||||
displacementPose.add(new Pose(globalDeltas.get(0, 0), globalDeltas.get(1, 0), globalDeltas.get(2, 0)));
|
||||
currentVelocity = new Pose(globalDeltas.get(0, 0) / (deltaTimeNano / Math.pow(10.0, 9)), globalDeltas.get(1, 0) / (deltaTimeNano / Math.pow(10.0, 9)), globalDeltas.get(2, 0) / (deltaTimeNano / Math.pow(10.0, 9)));
|
||||
currentVelocity = new Pose(globalDeltas.get(0, 0) / (deltaTimeNano * Math.pow(10.0, 9)), globalDeltas.get(1, 0) / (deltaTimeNano * Math.pow(10.0, 9)), globalDeltas.get(2, 0) / (deltaTimeNano * Math.pow(10.0, 9)));
|
||||
|
||||
totalHeading += globalDeltas.get(2, 0);
|
||||
}
|
||||
|
@ -1,5 +1,8 @@
|
||||
package org.firstinspires.ftc.teamcode.pedroPathing.localization.localizers;
|
||||
|
||||
import static org.firstinspires.ftc.teamcode.PedroConstants.BACK_ENCODER;
|
||||
import static org.firstinspires.ftc.teamcode.PedroConstants.LEFT_ENCODER;
|
||||
|
||||
import com.acmerobotics.dashboard.config.Config;
|
||||
import com.qualcomm.hardware.rev.RevHubOrientationOnRobot;
|
||||
import com.qualcomm.robotcore.hardware.DcMotorEx;
|
||||
@ -26,18 +29,18 @@ import org.firstinspires.ftc.teamcode.pedroPathing.util.NanoTimer;
|
||||
*
|
||||
* forward on robot is the x positive direction
|
||||
*
|
||||
* forward (x positive)
|
||||
* △
|
||||
* |
|
||||
* |
|
||||
* /--------------\
|
||||
* | |
|
||||
* | |
|
||||
* | || |
|
||||
* left (y positive) <--- | || |
|
||||
* | ____ |
|
||||
* | ---- |
|
||||
* \--------------/
|
||||
* /--------------\
|
||||
* | ____ |
|
||||
* | ---- |
|
||||
* | || || |
|
||||
* | || || | ----> left (y positive)
|
||||
* | |
|
||||
* | |
|
||||
* \--------------/
|
||||
* |
|
||||
* |
|
||||
* V
|
||||
* forward (x positive)
|
||||
*
|
||||
* @author Anyi Lin - 10158 Scott's Bots
|
||||
* @version 1.0, 4/2/2024
|
||||
@ -91,8 +94,8 @@ public class TwoWheelLocalizer extends Localizer { // todo: make two wheel odo w
|
||||
imu.initialize(new IMU.Parameters(new RevHubOrientationOnRobot(RevHubOrientationOnRobot.LogoFacingDirection.UP, RevHubOrientationOnRobot.UsbFacingDirection.LEFT)));
|
||||
|
||||
// TODO: replace these with your encoder ports
|
||||
forwardEncoder = new Encoder(hardwareMap.get(DcMotorEx.class, "leftRear"));
|
||||
strafeEncoder = new Encoder(hardwareMap.get(DcMotorEx.class, "strafeEncoder"));
|
||||
forwardEncoder = new Encoder(hardwareMap.get(DcMotorEx.class, LEFT_ENCODER));
|
||||
strafeEncoder = new Encoder(hardwareMap.get(DcMotorEx.class, BACK_ENCODER));
|
||||
|
||||
// TODO: reverse any encoders necessary
|
||||
forwardEncoder.setDirection(Encoder.REVERSE);
|
||||
@ -208,7 +211,7 @@ public class TwoWheelLocalizer extends Localizer { // todo: make two wheel odo w
|
||||
globalDeltas = Matrix.multiply(Matrix.multiply(prevRotationMatrix, transformation), robotDeltas);
|
||||
|
||||
displacementPose.add(new Pose(globalDeltas.get(0, 0), globalDeltas.get(1, 0), globalDeltas.get(2, 0)));
|
||||
currentVelocity = new Pose(globalDeltas.get(0, 0) / (deltaTimeNano / Math.pow(10.0, 9)), globalDeltas.get(1, 0) / (deltaTimeNano / Math.pow(10.0, 9)), globalDeltas.get(2, 0) / (deltaTimeNano / Math.pow(10.0, 9)));
|
||||
currentVelocity = new Pose(globalDeltas.get(0, 0) / (deltaTimeNano * Math.pow(10.0, 9)), globalDeltas.get(1, 0) / (deltaTimeNano * Math.pow(10.0, 9)), globalDeltas.get(2, 0) / (deltaTimeNano * Math.pow(10.0, 9)));
|
||||
|
||||
totalHeading += globalDeltas.get(2, 0);
|
||||
}
|
||||
@ -296,14 +299,4 @@ public class TwoWheelLocalizer extends Localizer { // todo: make two wheel odo w
|
||||
public void resetIMU() {
|
||||
imu.resetYaw();
|
||||
}
|
||||
|
||||
/**
|
||||
* This is returns the IMU.
|
||||
*
|
||||
* @return returns the IMU
|
||||
*/
|
||||
@Override
|
||||
public IMU getIMU() {
|
||||
return imu;
|
||||
}
|
||||
}
|
||||
|
@ -1,321 +0,0 @@
|
||||
package org.firstinspires.ftc.teamcode.pedroPathing.localization.localizers;
|
||||
|
||||
import com.acmerobotics.dashboard.config.Config;
|
||||
import com.qualcomm.robotcore.hardware.DcMotorEx;
|
||||
import com.qualcomm.robotcore.hardware.HardwareMap;
|
||||
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.localization.Encoder;
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.localization.GoBildaPinpointDriver;
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.localization.Localizer;
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.localization.Matrix;
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.localization.Pose;
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.pathGeneration.MathFunctions;
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.pathGeneration.Vector;
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.util.NanoTimer;
|
||||
|
||||
|
||||
/**
|
||||
* This is the TwoWheelPinpointIMULocalizer class. This class extends the Localizer superclass and is a
|
||||
* localizer that uses the two wheel odometry with the Pinpoint IMU set up. The diagram below, which is modified from
|
||||
* Road Runner, shows a typical set up.
|
||||
*
|
||||
* The view is from the top of the robot looking downwards.
|
||||
*
|
||||
* left on robot is the y positive direction
|
||||
*
|
||||
* forward on robot is the x positive direction
|
||||
*
|
||||
* forward (x positive)
|
||||
* △
|
||||
* |
|
||||
* |
|
||||
* /--------------\
|
||||
* | |
|
||||
* | |
|
||||
* | || |
|
||||
* left (y positive) <--- | || |
|
||||
* | ____ |
|
||||
* | ---- |
|
||||
* \--------------/
|
||||
*
|
||||
* @author Anyi Lin - 10158 Scott's Bots
|
||||
* @author Havish Sripada - 12808 RevAmped Robotics
|
||||
* @author Baron Henderson - 20077 The Indubitables
|
||||
* @version 1.0, 11/28/2024
|
||||
*/
|
||||
@Config
|
||||
public class TwoWheelPinpointIMULocalizer extends Localizer {
|
||||
private HardwareMap hardwareMap;
|
||||
private GoBildaPinpointDriver pinpoint;
|
||||
private Pose startPose;
|
||||
private Pose displacementPose;
|
||||
private Pose currentVelocity;
|
||||
private Matrix prevRotationMatrix;
|
||||
private NanoTimer timer;
|
||||
private long deltaTimeNano;
|
||||
private Encoder forwardEncoder;
|
||||
private Encoder strafeEncoder;
|
||||
private Pose forwardEncoderPose;
|
||||
private Pose strafeEncoderPose;
|
||||
private double previousHeading;
|
||||
private double deltaRadians;
|
||||
private double totalHeading;
|
||||
public static double FORWARD_TICKS_TO_INCHES = 8192 * 1.37795 * 2 * Math.PI * 0.5008239963;
|
||||
public static double STRAFE_TICKS_TO_INCHES = 8192 * 1.37795 * 2 * Math.PI * 0.5018874659;
|
||||
|
||||
/**
|
||||
* This creates a new TwoWheelLocalizer from a HardwareMap, with a starting Pose at (0,0)
|
||||
* facing 0 heading.
|
||||
*
|
||||
* @param map the HardwareMap
|
||||
*/
|
||||
public TwoWheelPinpointIMULocalizer(HardwareMap map) {
|
||||
this(map, new Pose());
|
||||
}
|
||||
|
||||
/**
|
||||
* This creates a new TwoWheelLocalizer from a HardwareMap and a Pose, with the Pose
|
||||
* specifying the starting pose of the localizer.
|
||||
*
|
||||
* @param map the HardwareMap
|
||||
* @param setStartPose the Pose to start from
|
||||
*/
|
||||
public TwoWheelPinpointIMULocalizer(HardwareMap map, Pose setStartPose) {
|
||||
// TODO: replace these with your encoder positions
|
||||
forwardEncoderPose = new Pose(-0.82, 6.47, 0);
|
||||
strafeEncoderPose = new Pose(-4, -0.273, Math.toRadians(90));
|
||||
|
||||
hardwareMap = map;
|
||||
|
||||
pinpoint = hardwareMap.get(GoBildaPinpointDriver.class, "pinpoint");
|
||||
pinpoint.resetPosAndIMU();
|
||||
|
||||
// TODO: replace these with your encoder ports
|
||||
forwardEncoder = new Encoder(hardwareMap.get(DcMotorEx.class, "leftRear"));
|
||||
strafeEncoder = new Encoder(hardwareMap.get(DcMotorEx.class, "strafeEncoder"));
|
||||
|
||||
// TODO: reverse any encoders necessary
|
||||
forwardEncoder.setDirection(Encoder.REVERSE);
|
||||
strafeEncoder.setDirection(Encoder.FORWARD);
|
||||
|
||||
setStartPose(setStartPose);
|
||||
timer = new NanoTimer();
|
||||
deltaTimeNano = 1;
|
||||
displacementPose = new Pose();
|
||||
currentVelocity = new Pose();
|
||||
previousHeading = startPose.getHeading();
|
||||
deltaRadians = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* This returns the current pose estimate.
|
||||
*
|
||||
* @return returns the current pose estimate as a Pose
|
||||
*/
|
||||
@Override
|
||||
public Pose getPose() {
|
||||
return new Pose(startPose.getX()+displacementPose.getX(), startPose.getY()+displacementPose.getY(),displacementPose.getHeading());
|
||||
}
|
||||
|
||||
/**
|
||||
* This returns the current velocity estimate.
|
||||
*
|
||||
* @return returns the current velocity estimate as a Pose
|
||||
*/
|
||||
@Override
|
||||
public Pose getVelocity() {
|
||||
return currentVelocity.copy();
|
||||
}
|
||||
|
||||
/**
|
||||
* This returns the current velocity estimate.
|
||||
*
|
||||
* @return returns the current velocity estimate as a Vector
|
||||
*/
|
||||
@Override
|
||||
public Vector getVelocityVector() {
|
||||
return currentVelocity.getVector();
|
||||
}
|
||||
|
||||
/**
|
||||
* This sets the start pose. Changing the start pose should move the robot as if all its
|
||||
* previous movements were displacing it from its new start pose.
|
||||
*
|
||||
* @param setStart the new start pose
|
||||
*/
|
||||
@Override
|
||||
public void setStartPose(Pose setStart) {
|
||||
startPose = setStart;
|
||||
}
|
||||
|
||||
/**
|
||||
* This sets the Matrix that contains the previous pose's heading rotation.
|
||||
*
|
||||
* @param heading the rotation of the Matrix
|
||||
*/
|
||||
public void setPrevRotationMatrix(double heading) {
|
||||
prevRotationMatrix = new Matrix(3, 3);
|
||||
prevRotationMatrix.set(0, 0, Math.cos(heading));
|
||||
prevRotationMatrix.set(0, 1, -Math.sin(heading));
|
||||
prevRotationMatrix.set(1, 0, Math.sin(heading));
|
||||
prevRotationMatrix.set(1, 1, Math.cos(heading));
|
||||
prevRotationMatrix.set(2, 2, 1.0);
|
||||
}
|
||||
|
||||
/**
|
||||
* This sets the current pose estimate. Changing this should just change the robot's current
|
||||
* pose estimate, not anything to do with the start pose.
|
||||
*
|
||||
* @param setPose the new current pose estimate
|
||||
*/
|
||||
@Override
|
||||
public void setPose(Pose setPose) {
|
||||
displacementPose = MathFunctions.subtractPoses(setPose, startPose);
|
||||
resetEncoders();
|
||||
}
|
||||
|
||||
/**
|
||||
* This updates the elapsed time timer that keeps track of time between updates, as well as the
|
||||
* change position of the Encoders and the IMU readings. Then, the robot's global change in
|
||||
* position is calculated using the pose exponential method.
|
||||
*/
|
||||
@Override
|
||||
public void update() {
|
||||
deltaTimeNano = timer.getElapsedTime();
|
||||
timer.resetTimer();
|
||||
|
||||
updateEncoders();
|
||||
Matrix robotDeltas = getRobotDeltas();
|
||||
Matrix globalDeltas;
|
||||
setPrevRotationMatrix(getPose().getHeading());
|
||||
|
||||
Matrix transformation = new Matrix(3, 3);
|
||||
if (Math.abs(robotDeltas.get(2, 0)) < 0.001) {
|
||||
transformation.set(0, 0, 1.0 - (Math.pow(robotDeltas.get(2, 0), 2) / 6.0));
|
||||
transformation.set(0, 1, -robotDeltas.get(2, 0) / 2.0);
|
||||
transformation.set(1, 0, robotDeltas.get(2, 0) / 2.0);
|
||||
transformation.set(1, 1, 1.0 - (Math.pow(robotDeltas.get(2, 0), 2) / 6.0));
|
||||
transformation.set(2, 2, 1.0);
|
||||
} else {
|
||||
transformation.set(0, 0, Math.sin(robotDeltas.get(2, 0)) / robotDeltas.get(2, 0));
|
||||
transformation.set(0, 1, (Math.cos(robotDeltas.get(2, 0)) - 1.0) / robotDeltas.get(2, 0));
|
||||
transformation.set(1, 0, (1.0 - Math.cos(robotDeltas.get(2, 0))) / robotDeltas.get(2, 0));
|
||||
transformation.set(1, 1, Math.sin(robotDeltas.get(2, 0)) / robotDeltas.get(2, 0));
|
||||
transformation.set(2, 2, 1.0);
|
||||
}
|
||||
|
||||
globalDeltas = Matrix.multiply(Matrix.multiply(prevRotationMatrix, transformation), robotDeltas);
|
||||
|
||||
displacementPose.add(new Pose(globalDeltas.get(0, 0), globalDeltas.get(1, 0), globalDeltas.get(2, 0)));
|
||||
currentVelocity = new Pose(globalDeltas.get(0, 0) / (deltaTimeNano / Math.pow(10.0, 9)), globalDeltas.get(1, 0) / (deltaTimeNano / Math.pow(10.0, 9)), globalDeltas.get(2, 0) / (deltaTimeNano / Math.pow(10.0, 9)));
|
||||
|
||||
totalHeading += globalDeltas.get(2, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* This updates the Encoders as well as the IMU.
|
||||
*/
|
||||
public void updateEncoders() {
|
||||
forwardEncoder.update();
|
||||
strafeEncoder.update();
|
||||
|
||||
pinpoint.update(GoBildaPinpointDriver.readData.ONLY_UPDATE_HEADING);
|
||||
double currentHeading = startPose.getHeading() + MathFunctions.normalizeAngle(pinpoint.getHeading());
|
||||
deltaRadians = MathFunctions.getTurnDirection(previousHeading, currentHeading) * MathFunctions.getSmallestAngleDifference(currentHeading, previousHeading);
|
||||
previousHeading = currentHeading;
|
||||
}
|
||||
|
||||
/**
|
||||
* This resets the Encoders.
|
||||
*/
|
||||
public void resetEncoders() {
|
||||
forwardEncoder.reset();
|
||||
strafeEncoder.reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* This calculates the change in position from the perspective of the robot using information
|
||||
* from the Encoders and IMU.
|
||||
*
|
||||
* @return returns a Matrix containing the robot relative movement.
|
||||
*/
|
||||
public Matrix getRobotDeltas() {
|
||||
Matrix returnMatrix = new Matrix(3, 1);
|
||||
// x/forward movement
|
||||
returnMatrix.set(0, 0, FORWARD_TICKS_TO_INCHES * (forwardEncoder.getDeltaPosition() - forwardEncoderPose.getY() * deltaRadians));
|
||||
//y/strafe movement
|
||||
returnMatrix.set(1, 0, STRAFE_TICKS_TO_INCHES * (strafeEncoder.getDeltaPosition() - strafeEncoderPose.getX() * deltaRadians));
|
||||
// theta/turning
|
||||
returnMatrix.set(2, 0, deltaRadians);
|
||||
return returnMatrix;
|
||||
}
|
||||
|
||||
/**
|
||||
* This returns how far the robot has turned in radians, in a number not clamped between 0 and
|
||||
* 2 * pi radians. This is used for some tuning things and nothing actually within the following.
|
||||
*
|
||||
* @return returns how far the robot has turned in total, in radians.
|
||||
*/
|
||||
public double getTotalHeading() {
|
||||
return totalHeading;
|
||||
}
|
||||
|
||||
/**
|
||||
* This returns the multiplier applied to forward movement measurement to convert from encoder
|
||||
* ticks to inches. This is found empirically through a tuner.
|
||||
*
|
||||
* @return returns the forward ticks to inches multiplier
|
||||
*/
|
||||
public double getForwardMultiplier() {
|
||||
return FORWARD_TICKS_TO_INCHES;
|
||||
}
|
||||
|
||||
/**
|
||||
* This returns the multiplier applied to lateral/strafe movement measurement to convert from
|
||||
* encoder ticks to inches. This is found empirically through a tuner.
|
||||
*
|
||||
* @return returns the lateral/strafe ticks to inches multiplier
|
||||
*/
|
||||
public double getLateralMultiplier() {
|
||||
return STRAFE_TICKS_TO_INCHES;
|
||||
}
|
||||
|
||||
/**
|
||||
* This returns the multiplier applied to turning movement measurement to convert from encoder
|
||||
* ticks to radians. This is found empirically through a tuner.
|
||||
*
|
||||
* @return returns the turning ticks to radians multiplier
|
||||
*/
|
||||
public double getTurningMultiplier() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* This resets the IMU.
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void resetIMU() throws InterruptedException {
|
||||
pinpoint.recalibrateIMU();
|
||||
|
||||
try {
|
||||
Thread.sleep(300);
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This resets the pinpoint.
|
||||
*/
|
||||
private void resetPinpoint() throws InterruptedException{
|
||||
pinpoint.resetPosAndIMU();
|
||||
|
||||
try {
|
||||
Thread.sleep(300);
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package org.firstinspires.ftc.teamcode.pedroPathing.localization.tuning;
|
||||
import com.acmerobotics.dashboard.FtcDashboard;
|
||||
import com.acmerobotics.dashboard.config.Config;
|
||||
import com.acmerobotics.dashboard.telemetry.MultipleTelemetry;
|
||||
import com.acmerobotics.dashboard.telemetry.TelemetryPacket;
|
||||
import com.qualcomm.robotcore.eventloop.opmode.Autonomous;
|
||||
import com.qualcomm.robotcore.eventloop.opmode.OpMode;
|
||||
|
||||
@ -26,13 +27,13 @@ import org.firstinspires.ftc.teamcode.pedroPathing.util.Drawing;
|
||||
*/
|
||||
@Config
|
||||
@Autonomous(name = "Forward Localizer Tuner", group = "Autonomous Pathing Tuning")
|
||||
public class ForwardTuner extends OpMode {
|
||||
public class FowardTuner extends OpMode {
|
||||
private PoseUpdater poseUpdater;
|
||||
private DashboardPoseTracker dashboardPoseTracker;
|
||||
|
||||
private Telemetry telemetryA;
|
||||
|
||||
public static double DISTANCE = 48;
|
||||
public static double DISTANCE = 30;
|
||||
|
||||
/**
|
||||
* This initializes the PoseUpdater as well as the FTC Dashboard telemetry.
|
@ -33,7 +33,7 @@ public class LateralTuner extends OpMode {
|
||||
|
||||
private Telemetry telemetryA;
|
||||
|
||||
public static double DISTANCE = 48;
|
||||
public static double DISTANCE = 30;
|
||||
|
||||
/**
|
||||
* This initializes the PoseUpdater as well as the FTC Dashboard telemetry.
|
||||
@ -63,6 +63,7 @@ public class LateralTuner extends OpMode {
|
||||
telemetryA.addData("distance moved", poseUpdater.getPose().getY());
|
||||
telemetryA.addLine("The multiplier will display what your strafe ticks to inches should be to scale your current distance to " + DISTANCE + " inches.");
|
||||
telemetryA.addData("multiplier", DISTANCE / (poseUpdater.getPose().getY() / poseUpdater.getLocalizer().getLateralMultiplier()));
|
||||
|
||||
telemetryA.update();
|
||||
|
||||
Drawing.drawPoseHistory(dashboardPoseTracker, "#4CAF50");
|
||||
|
@ -4,10 +4,6 @@ import static org.firstinspires.ftc.teamcode.pedroPathing.tuning.FollowerConstan
|
||||
import static org.firstinspires.ftc.teamcode.pedroPathing.tuning.FollowerConstants.leftRearMotorName;
|
||||
import static org.firstinspires.ftc.teamcode.pedroPathing.tuning.FollowerConstants.rightFrontMotorName;
|
||||
import static org.firstinspires.ftc.teamcode.pedroPathing.tuning.FollowerConstants.rightRearMotorName;
|
||||
import static org.firstinspires.ftc.teamcode.pedroPathing.tuning.FollowerConstants.leftFrontMotorDirection;
|
||||
import static org.firstinspires.ftc.teamcode.pedroPathing.tuning.FollowerConstants.leftRearMotorDirection;
|
||||
import static org.firstinspires.ftc.teamcode.pedroPathing.tuning.FollowerConstants.rightFrontMotorDirection;
|
||||
import static org.firstinspires.ftc.teamcode.pedroPathing.tuning.FollowerConstants.rightRearMotorDirection;
|
||||
|
||||
import com.acmerobotics.dashboard.FtcDashboard;
|
||||
import com.acmerobotics.dashboard.config.Config;
|
||||
@ -16,6 +12,7 @@ import com.qualcomm.robotcore.eventloop.opmode.OpMode;
|
||||
import com.qualcomm.robotcore.eventloop.opmode.TeleOp;
|
||||
import com.qualcomm.robotcore.hardware.DcMotor;
|
||||
import com.qualcomm.robotcore.hardware.DcMotorEx;
|
||||
import com.qualcomm.robotcore.hardware.DcMotorSimple;
|
||||
import com.qualcomm.robotcore.hardware.configuration.typecontainers.MotorConfigurationType;
|
||||
|
||||
import org.firstinspires.ftc.robotcore.external.Telemetry;
|
||||
@ -60,10 +57,9 @@ public class LocalizationTest extends OpMode {
|
||||
leftRear = hardwareMap.get(DcMotorEx.class, leftRearMotorName);
|
||||
rightRear = hardwareMap.get(DcMotorEx.class, rightRearMotorName);
|
||||
rightFront = hardwareMap.get(DcMotorEx.class, rightFrontMotorName);
|
||||
leftFront.setDirection(leftFrontMotorDirection);
|
||||
leftRear.setDirection(leftRearMotorDirection);
|
||||
rightFront.setDirection(rightFrontMotorDirection);
|
||||
rightRear.setDirection(rightRearMotorDirection);
|
||||
|
||||
leftFront.setDirection(DcMotorSimple.Direction.REVERSE);
|
||||
leftRear.setDirection(DcMotorSimple.Direction.REVERSE);
|
||||
|
||||
motors = Arrays.asList(leftFront, leftRear, rightFront, rightRear);
|
||||
|
||||
|
@ -1,200 +0,0 @@
|
||||
/* MIT License
|
||||
* Copyright (c) [2024] [Base 10 Assets, LLC]
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.firstinspires.ftc.teamcode.pedroPathing.localization.tuning;
|
||||
|
||||
import com.qualcomm.robotcore.eventloop.opmode.Disabled;
|
||||
import com.qualcomm.robotcore.eventloop.opmode.LinearOpMode;
|
||||
import com.qualcomm.robotcore.eventloop.opmode.TeleOp;
|
||||
|
||||
import org.firstinspires.ftc.robotcore.external.navigation.AngleUnit;
|
||||
import org.firstinspires.ftc.robotcore.external.navigation.DistanceUnit;
|
||||
import org.firstinspires.ftc.robotcore.external.navigation.Pose2D;
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.localization.GoBildaPinpointDriver;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
/*
|
||||
This opmode shows how to use the goBILDA® Pinpoint Odometry Computer.
|
||||
The goBILDA Odometry Computer is a device designed to solve the Pose Exponential calculation
|
||||
commonly associated with Dead Wheel Odometry systems. It reads two encoders, and an integrated
|
||||
system of senors to determine the robot's current heading, X position, and Y position.
|
||||
|
||||
it uses an ESP32-S3 as a main cpu, with an STM LSM6DSV16X IMU.
|
||||
It is validated with goBILDA "Dead Wheel" Odometry pods, but should be compatible with any
|
||||
quadrature rotary encoder. The ESP32 PCNT peripheral is speced to decode quadrature encoder signals
|
||||
at a maximum of 40mhz per channel. Though the maximum in-application tested number is 130khz.
|
||||
|
||||
The device expects two perpendicularly mounted Dead Wheel pods. The encoder pulses are translated
|
||||
into mm and their readings are transformed by an "offset", this offset describes how far away
|
||||
the pods are from the "tracking point", usually the center of rotation of the robot.
|
||||
|
||||
Dead Wheel pods should both increase in count when moved forwards and to the left.
|
||||
The gyro will report an increase in heading when rotated counterclockwise.
|
||||
|
||||
The Pose Exponential algorithm used is described on pg 181 of this book:
|
||||
https://github.com/calcmogul/controls-engineering-in-frc
|
||||
|
||||
For support, contact tech@gobilda.com
|
||||
|
||||
-Ethan Doak
|
||||
*/
|
||||
|
||||
//TODO: If tuning comment out the @Disabled
|
||||
@TeleOp(name="goBILDA® PinPoint Odometry Example", group="Linear OpMode")
|
||||
@Disabled
|
||||
|
||||
public class SensorGoBildaPinpointExample extends LinearOpMode {
|
||||
|
||||
GoBildaPinpointDriver odo; // Declare OpMode member for the Odometry Computer
|
||||
|
||||
double oldTime = 0;
|
||||
|
||||
|
||||
@Override
|
||||
public void runOpMode() {
|
||||
|
||||
// Initialize the hardware variables. Note that the strings used here must correspond
|
||||
// to the names assigned during the robot configuration step on the DS or RC devices.
|
||||
|
||||
odo = hardwareMap.get(GoBildaPinpointDriver.class,"odo");
|
||||
|
||||
/*
|
||||
Set the odometry pod positions relative to the point that the odometry computer tracks around.
|
||||
The X pod offset refers to how far sideways from the tracking point the
|
||||
X (forward) odometry pod is. Left of the center is a positive number,
|
||||
right of center is a negative number. the Y pod offset refers to how far forwards from
|
||||
the tracking point the Y (strafe) odometry pod is. forward of center is a positive number,
|
||||
backwards is a negative number.
|
||||
*/
|
||||
odo.setOffsets(-84.0, -168.0); //these are tuned for 3110-0002-0001 Product Insight #1
|
||||
|
||||
/*
|
||||
Set the kind of pods used by your robot. If you're using goBILDA odometry pods, select either
|
||||
the goBILDA_SWINGARM_POD, or the goBILDA_4_BAR_POD.
|
||||
If you're using another kind of odometry pod, uncomment setEncoderResolution and input the
|
||||
number of ticks per mm of your odometry pod.
|
||||
*/
|
||||
odo.setEncoderResolution(GoBildaPinpointDriver.GoBildaOdometryPods.goBILDA_4_BAR_POD);
|
||||
//odo.setEncoderResolution(13.26291192);
|
||||
|
||||
|
||||
/*
|
||||
Set the direction that each of the two odometry pods count. The X (forward) pod should
|
||||
increase when you move the robot forward. And the Y (strafe) pod should increase when
|
||||
you move the robot to the left.
|
||||
*/
|
||||
odo.setEncoderDirections(GoBildaPinpointDriver.EncoderDirection.FORWARD, GoBildaPinpointDriver.EncoderDirection.FORWARD);
|
||||
|
||||
|
||||
/*
|
||||
Before running the robot, recalibrate the IMU. This needs to happen when the robot is stationary
|
||||
The IMU will automatically calibrate when first powered on, but recalibrating before running
|
||||
the robot is a good idea to ensure that the calibration is "good".
|
||||
resetPosAndIMU will reset the position to 0,0,0 and also recalibrate the IMU.
|
||||
This is recommended before you run your autonomous, as a bad initial calibration can cause
|
||||
an incorrect starting value for x, y, and heading.
|
||||
*/
|
||||
//odo.recalibrateIMU();
|
||||
odo.resetPosAndIMU();
|
||||
|
||||
telemetry.addData("Status", "Initialized");
|
||||
telemetry.addData("X offset", odo.getXOffset());
|
||||
telemetry.addData("Y offset", odo.getYOffset());
|
||||
telemetry.addData("Device Version Number:", odo.getDeviceVersion());
|
||||
telemetry.addData("Device Scalar", odo.getYawScalar());
|
||||
telemetry.update();
|
||||
|
||||
// Wait for the game to start (driver presses START)
|
||||
waitForStart();
|
||||
resetRuntime();
|
||||
|
||||
|
||||
// run until the end of the match (driver presses STOP)
|
||||
while (opModeIsActive()) {
|
||||
|
||||
/*
|
||||
Request an update from the Pinpoint odometry computer. This checks almost all outputs
|
||||
from the device in a single I2C read.
|
||||
*/
|
||||
odo.update();
|
||||
|
||||
/*
|
||||
Optionally, you can update only the heading of the device. This takes less time to read, but will not
|
||||
pull any other data. Only the heading (which you can pull with getHeading() or in getPosition().
|
||||
*/
|
||||
//odo.update(GoBildaPinpointDriver.readData.ONLY_UPDATE_HEADING);
|
||||
|
||||
|
||||
if (gamepad1.a){
|
||||
odo.resetPosAndIMU(); //resets the position to 0 and recalibrates the IMU
|
||||
}
|
||||
|
||||
if (gamepad1.b){
|
||||
odo.recalibrateIMU(); //recalibrates the IMU without resetting position
|
||||
}
|
||||
|
||||
/*
|
||||
This code prints the loop frequency of the REV Control Hub. This frequency is effected
|
||||
by I²C reads/writes. So it's good to keep an eye on. This code calculates the amount
|
||||
of time each cycle takes and finds the frequency (number of updates per second) from
|
||||
that cycle time.
|
||||
*/
|
||||
double newTime = getRuntime();
|
||||
double loopTime = newTime-oldTime;
|
||||
double frequency = 1/loopTime;
|
||||
oldTime = newTime;
|
||||
|
||||
|
||||
/*
|
||||
gets the current Position (x & y in mm, and heading in degrees) of the robot, and prints it.
|
||||
*/
|
||||
Pose2D pos = odo.getPosition();
|
||||
String data = String.format(Locale.US, "{X: %.3f, Y: %.3f, H: %.3f}", pos.getX(DistanceUnit.MM), pos.getY(DistanceUnit.MM), pos.getHeading(AngleUnit.DEGREES));
|
||||
telemetry.addData("Position", data);
|
||||
|
||||
/*
|
||||
gets the current Velocity (x & y in mm/sec and heading in degrees/sec) and prints it.
|
||||
*/
|
||||
Pose2D vel = odo.getVelocity();
|
||||
String velocity = String.format(Locale.US,"{XVel: %.3f, YVel: %.3f, HVel: %.3f}", vel.getX(DistanceUnit.MM), vel.getY(DistanceUnit.MM), vel.getHeading(AngleUnit.DEGREES));
|
||||
telemetry.addData("Velocity", velocity);
|
||||
|
||||
|
||||
/*
|
||||
Gets the Pinpoint device status. Pinpoint can reflect a few states. But we'll primarily see
|
||||
READY: the device is working as normal
|
||||
CALIBRATING: the device is calibrating and outputs are put on hold
|
||||
NOT_READY: the device is resetting from scratch. This should only happen after a power-cycle
|
||||
FAULT_NO_PODS_DETECTED - the device does not detect any pods plugged in
|
||||
FAULT_X_POD_NOT_DETECTED - The device does not detect an X pod plugged in
|
||||
FAULT_Y_POD_NOT_DETECTED - The device does not detect a Y pod plugged in
|
||||
*/
|
||||
telemetry.addData("Status", odo.getDeviceStatus());
|
||||
|
||||
telemetry.addData("Pinpoint Frequency", odo.getFrequency()); //prints/gets the current refresh rate of the Pinpoint
|
||||
|
||||
telemetry.addData("REV Hub Frequency: ", frequency); //prints the control system refresh rate
|
||||
telemetry.update();
|
||||
|
||||
}
|
||||
}}
|
@ -27,16 +27,16 @@ public class MathFunctions {
|
||||
double denom = 1;
|
||||
|
||||
// this multiplies up the numerator of the nCr function
|
||||
for (int i = n; i > n - r; i--) {
|
||||
for (int i = n; i > n-r; i--) {
|
||||
num *= i;
|
||||
}
|
||||
|
||||
// this multiplies up the denominator of the nCr function
|
||||
for (int i = 1; i <= r; i++) {
|
||||
for (int i = 1; i <=r; i++) {
|
||||
denom *= i;
|
||||
}
|
||||
|
||||
return num / denom;
|
||||
return num/denom;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -67,7 +67,7 @@ public class MathFunctions {
|
||||
|
||||
/**
|
||||
* This normalizes an angle to be between 0 and 2 pi radians, inclusive.
|
||||
* <p>
|
||||
*
|
||||
* IMPORTANT NOTE: This method operates in radians.
|
||||
*
|
||||
* @param angleRadians the angle to be normalized.
|
||||
@ -75,8 +75,8 @@ public class MathFunctions {
|
||||
*/
|
||||
public static double normalizeAngle(double angleRadians) {
|
||||
double angle = angleRadians;
|
||||
while (angle < 0) angle += 2 * Math.PI;
|
||||
while (angle > 2 * Math.PI) angle -= 2 * Math.PI;
|
||||
while (angle<0) angle += 2*Math.PI;
|
||||
while (angle>2*Math.PI) angle -= 2*Math.PI;
|
||||
return angle;
|
||||
}
|
||||
|
||||
@ -88,7 +88,7 @@ public class MathFunctions {
|
||||
* @return returns the smallest angle.
|
||||
*/
|
||||
public static double getSmallestAngleDifference(double one, double two) {
|
||||
return Math.min(MathFunctions.normalizeAngle(one - two), MathFunctions.normalizeAngle(two - one));
|
||||
return Math.min(MathFunctions.normalizeAngle(one-two), MathFunctions.normalizeAngle(two-one));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -98,7 +98,7 @@ public class MathFunctions {
|
||||
* @return returns the turn direction.
|
||||
*/
|
||||
public static double getTurnDirection(double startHeading, double endHeading) {
|
||||
if (MathFunctions.normalizeAngle(endHeading - startHeading) >= 0 && MathFunctions.normalizeAngle(endHeading - startHeading) <= Math.PI) {
|
||||
if (MathFunctions.normalizeAngle(endHeading-startHeading) >= 0 && MathFunctions.normalizeAngle(endHeading-startHeading) <= Math.PI) {
|
||||
return 1; // counter clock wise
|
||||
}
|
||||
return -1; // clock wise
|
||||
@ -112,7 +112,7 @@ public class MathFunctions {
|
||||
* @return returns the distance between the two.
|
||||
*/
|
||||
public static double distance(Pose pose, Point point) {
|
||||
return Math.sqrt(Math.pow(pose.getX() - point.getX(), 2) + Math.pow(pose.getY() - point.getY(), 2));
|
||||
return Math.sqrt(Math.pow(pose.getX()-point.getX(), 2) + Math.pow(pose.getY()-point.getY(), 2));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -123,7 +123,7 @@ public class MathFunctions {
|
||||
* @return returns the distance between the two.
|
||||
*/
|
||||
public static double distance(Pose one, Pose two) {
|
||||
return Math.sqrt(Math.pow(one.getX() - two.getX(), 2) + Math.pow(one.getY() - two.getY(), 2));
|
||||
return Math.sqrt(Math.pow(one.getX()-two.getX(), 2) + Math.pow(one.getY()-two.getY(), 2));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -172,22 +172,6 @@ public class MathFunctions {
|
||||
return new Pose(one.getX() - two.getX(), one.getY() - two.getY(), one.getHeading() - two.getHeading());
|
||||
}
|
||||
|
||||
/**
|
||||
* This rotates the given pose by the given theta,
|
||||
*
|
||||
* @param pose the Pose to rotate.
|
||||
* @param theta the angle to rotate by.
|
||||
* @param rotateHeading whether to adjust the Pose heading too.
|
||||
* @return the rotated Pose.
|
||||
*/
|
||||
public static Pose rotatePose(Pose pose, double theta, boolean rotateHeading) {
|
||||
double x = pose.getX() * Math.cos(theta) - pose.getY() * Math.sin(theta);
|
||||
double y = pose.getX() * Math.sin(theta) + pose.getY() * Math.cos(theta);
|
||||
double heading = rotateHeading ? normalizeAngle(pose.getHeading() + theta) : pose.getHeading();
|
||||
|
||||
return new Pose(x, y, heading);
|
||||
}
|
||||
|
||||
/**
|
||||
* This multiplies a Point by a scalar and returns the result as a Point
|
||||
*
|
||||
@ -196,7 +180,7 @@ public class MathFunctions {
|
||||
* @return returns the scaled Point.
|
||||
*/
|
||||
public static Point scalarMultiplyPoint(Point point, double scalar) {
|
||||
return new Point(point.getX() * scalar, point.getY() * scalar, Point.CARTESIAN);
|
||||
return new Point(point.getX()*scalar, point.getY()*scalar, Point.CARTESIAN);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -229,7 +213,7 @@ public class MathFunctions {
|
||||
* @return returns the scaled Vector.
|
||||
*/
|
||||
public static Vector scalarMultiplyVector(Vector vector, double scalar) {
|
||||
return new Vector(vector.getMagnitude() * scalar, vector.getTheta());
|
||||
return new Vector(vector.getMagnitude()*scalar, vector.getTheta());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -243,7 +227,7 @@ public class MathFunctions {
|
||||
if (vector.getMagnitude() == 0) {
|
||||
return new Vector(0.0, vector.getTheta());
|
||||
} else {
|
||||
return new Vector(vector.getMagnitude() / Math.abs(vector.getMagnitude()), vector.getTheta());
|
||||
return new Vector(vector.getMagnitude()/Math.abs(vector.getMagnitude()), vector.getTheta());
|
||||
}
|
||||
}
|
||||
|
||||
@ -256,7 +240,7 @@ public class MathFunctions {
|
||||
*/
|
||||
public static Vector addVectors(Vector one, Vector two) {
|
||||
Vector returnVector = new Vector();
|
||||
returnVector.setOrthogonalComponents(one.getXComponent() + two.getXComponent(), one.getYComponent() + two.getYComponent());
|
||||
returnVector.setOrthogonalComponents(one.getXComponent()+two.getXComponent(), one.getYComponent()+two.getYComponent());
|
||||
return returnVector;
|
||||
}
|
||||
|
||||
@ -270,7 +254,7 @@ public class MathFunctions {
|
||||
*/
|
||||
public static Vector subtractVectors(Vector one, Vector two) {
|
||||
Vector returnVector = new Vector();
|
||||
returnVector.setOrthogonalComponents(one.getXComponent() - two.getXComponent(), one.getYComponent() - two.getYComponent());
|
||||
returnVector.setOrthogonalComponents(one.getXComponent()-two.getXComponent(), one.getYComponent()-two.getYComponent());
|
||||
return returnVector;
|
||||
}
|
||||
|
||||
@ -282,7 +266,7 @@ public class MathFunctions {
|
||||
* @return returns the dot product of the two Vectors.
|
||||
*/
|
||||
public static double dotProduct(Vector one, Vector two) {
|
||||
return one.getXComponent() * two.getXComponent() + one.getYComponent() * two.getYComponent();
|
||||
return one.getXComponent()*two.getXComponent() + one.getYComponent()*two.getYComponent();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -294,7 +278,7 @@ public class MathFunctions {
|
||||
* @return returns the cross product of the two Vectors.
|
||||
*/
|
||||
public static double crossProduct(Vector one, Vector two) {
|
||||
return one.getXComponent() * two.getYComponent() - one.getYComponent() * two.getXComponent();
|
||||
return one.getXComponent()*two.getYComponent() - one.getYComponent()*two.getXComponent();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -302,7 +286,7 @@ public class MathFunctions {
|
||||
* specified accuracy amount.
|
||||
*
|
||||
* @param one first number specified.
|
||||
* @param two Second number specified.
|
||||
* @param two second number specified.
|
||||
* @param accuracy the level of accuracy specified.
|
||||
* @return returns if the two numbers are within the specified accuracy of each other.
|
||||
*/
|
||||
|
@ -51,47 +51,16 @@ public class PathBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* This adds a default Path defined by a specified BezierCurve to the PathBuilder.
|
||||
*
|
||||
* @param controlPoints This is the specified control points that define the BezierCurve.
|
||||
* @return This returns itself with the updated data.
|
||||
*/
|
||||
public PathBuilder addBezierCurve(Point... controlPoints) {
|
||||
return addPath(new BezierCurve(controlPoints));
|
||||
}
|
||||
|
||||
/**
|
||||
* This adds a default Path defined by a specified BezierCurve to the PathBuilder.
|
||||
*
|
||||
* @param controlPoints This is the specified control points that define the BezierCurve.
|
||||
* @return This returns itself with the updated data.
|
||||
*/
|
||||
public PathBuilder addBezierCurve(ArrayList<Point> controlPoints) {
|
||||
return addPath(new BezierCurve(controlPoints));
|
||||
}
|
||||
|
||||
/**
|
||||
* This adds a default Path defined by a specified BezierLine to the PathBuilder.
|
||||
*
|
||||
* @param startPoint start point of the line.
|
||||
* @param endPoint end point of the line.
|
||||
* @return This returns itself with the updated data.
|
||||
*/
|
||||
public PathBuilder addBezierLine(Point startPoint, Point endPoint) {
|
||||
return addPath(new BezierLine(startPoint, endPoint));
|
||||
}
|
||||
|
||||
/**
|
||||
* This sets a linear heading interpolation on the last Path added to the PathBuilder.
|
||||
*
|
||||
* @param startHeading The start of the linear heading interpolation.
|
||||
* @param endHeading The end of the linear heading interpolation.
|
||||
* This will be reached at the end of the Path if no end time is specified.
|
||||
* This will be reached at the end of the Path if no end time is specified.
|
||||
* @return This returns itself with the updated data.
|
||||
*/
|
||||
public PathBuilder setLinearHeadingInterpolation(double startHeading, double endHeading) {
|
||||
this.paths.get(paths.size() - 1).setLinearHeadingInterpolation(startHeading, endHeading);
|
||||
this.paths.get(paths.size()-1).setLinearHeadingInterpolation(startHeading, endHeading);
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -100,13 +69,13 @@ public class PathBuilder {
|
||||
*
|
||||
* @param startHeading The start of the linear heading interpolation.
|
||||
* @param endHeading The end of the linear heading interpolation.
|
||||
* This will be reached at the end of the Path if no end time is specified.
|
||||
* This will be reached at the end of the Path if no end time is specified.
|
||||
* @param endTime The end time on the Path that the linear heading interpolation will end.
|
||||
* This value goes from [0, 1] since Bezier curves are parametric functions.
|
||||
* This value goes from [0, 1] since Bezier curves are parametric functions.
|
||||
* @return This returns itself with the updated data.
|
||||
*/
|
||||
public PathBuilder setLinearHeadingInterpolation(double startHeading, double endHeading, double endTime) {
|
||||
this.paths.get(paths.size() - 1).setLinearHeadingInterpolation(startHeading, endHeading, endTime);
|
||||
this.paths.get(paths.size()-1).setLinearHeadingInterpolation(startHeading, endHeading, endTime);
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -117,7 +86,7 @@ public class PathBuilder {
|
||||
* @return This returns itself with the updated data.
|
||||
*/
|
||||
public PathBuilder setConstantHeadingInterpolation(double setHeading) {
|
||||
this.paths.get(paths.size() - 1).setConstantHeadingInterpolation(setHeading);
|
||||
this.paths.get(paths.size()-1).setConstantHeadingInterpolation(setHeading);
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -125,21 +94,20 @@ public class PathBuilder {
|
||||
* This sets a reversed or tangent heading interpolation on the last Path added to the PathBuilder.
|
||||
*
|
||||
* @param set This sets the heading to reversed tangent following if this parameter is true.
|
||||
* Conversely, this sets a tangent following if this parameter is false.
|
||||
* Conversely, this sets a tangent following if this parameter is false.
|
||||
* @return This returns itself with the updated data.
|
||||
*/
|
||||
public PathBuilder setReversed(boolean set) {
|
||||
this.paths.get(paths.size() - 1).setReversed(set);
|
||||
this.paths.get(paths.size()-1).setReversed(set);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* This sets the heading interpolation to tangential on the last Path added to the PathBuilder.
|
||||
* There really shouldn't be a reason to use this since the default heading interpolation is
|
||||
* tangential but it's here.
|
||||
*/
|
||||
public PathBuilder setTangentHeadingInterpolation() {
|
||||
this.paths.get(paths.size() - 1).setTangentHeadingInterpolation();
|
||||
this.paths.get(paths.size()-1).setTangentHeadingInterpolation();
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -150,7 +118,7 @@ public class PathBuilder {
|
||||
* @return This returns itself with the updated data.
|
||||
*/
|
||||
public PathBuilder setZeroPowerAccelerationMultiplier(double set) {
|
||||
this.paths.get(paths.size() - 1).setZeroPowerAccelerationMultiplier(set);
|
||||
this.paths.get(paths.size()-1).setZeroPowerAccelerationMultiplier(set);
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -161,7 +129,7 @@ public class PathBuilder {
|
||||
* @return This returns itself with the updated data.
|
||||
*/
|
||||
public PathBuilder setPathEndVelocityConstraint(double set) {
|
||||
this.paths.get(paths.size() - 1).setPathEndVelocityConstraint(set);
|
||||
this.paths.get(paths.size()-1).setPathEndVelocityConstraint(set);
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -172,7 +140,7 @@ public class PathBuilder {
|
||||
* @return This returns itself with the updated data.
|
||||
*/
|
||||
public PathBuilder setPathEndTranslationalConstraint(double set) {
|
||||
this.paths.get(paths.size() - 1).setPathEndTranslationalConstraint(set);
|
||||
this.paths.get(paths.size()-1).setPathEndTranslationalConstraint(set);
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -183,7 +151,7 @@ public class PathBuilder {
|
||||
* @return This returns itself with the updated data.
|
||||
*/
|
||||
public PathBuilder setPathEndHeadingConstraint(double set) {
|
||||
this.paths.get(paths.size() - 1).setPathEndHeadingConstraint(set);
|
||||
this.paths.get(paths.size()-1).setPathEndHeadingConstraint(set);
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -194,7 +162,7 @@ public class PathBuilder {
|
||||
* @return This returns itself with the updated data.
|
||||
*/
|
||||
public PathBuilder setPathEndTValueConstraint(double set) {
|
||||
this.paths.get(paths.size() - 1).setPathEndTValueConstraint(set);
|
||||
this.paths.get(paths.size()-1).setPathEndTValueConstraint(set);
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -205,7 +173,7 @@ public class PathBuilder {
|
||||
* @return This returns itself with the updated data.
|
||||
*/
|
||||
public PathBuilder setPathEndTimeoutConstraint(double set) {
|
||||
this.paths.get(paths.size() - 1).setPathEndTimeoutConstraint(set);
|
||||
this.paths.get(paths.size()-1).setPathEndTimeoutConstraint(set);
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -214,12 +182,12 @@ public class PathBuilder {
|
||||
* This callback is set to run at a specified number of milliseconds after the start of the path.
|
||||
*
|
||||
* @param time This sets the number of milliseconds of wait between the start of the Path and
|
||||
* the calling of the callback.
|
||||
* the calling of the callback.
|
||||
* @param runnable This sets the code for the callback to run. Use lambda statements for this.
|
||||
* @return This returns itself with the updated data.
|
||||
*/
|
||||
public PathBuilder addTemporalCallback(double time, Runnable runnable) {
|
||||
this.callbacks.add(new PathCallback(time, runnable, PathCallback.TIME, paths.size() - 1));
|
||||
this.callbacks.add(new PathCallback(time, runnable, PathCallback.TIME, paths.size()-1));
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -232,7 +200,7 @@ public class PathBuilder {
|
||||
* @return This returns itself with the updated data.
|
||||
*/
|
||||
public PathBuilder addParametricCallback(double t, Runnable runnable) {
|
||||
this.callbacks.add(new PathCallback(t, runnable, PathCallback.PARAMETRIC, paths.size() - 1));
|
||||
this.callbacks.add(new PathCallback(t, runnable, PathCallback.PARAMETRIC, paths.size()-1));
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,5 @@
|
||||
package org.firstinspires.ftc.teamcode.pedroPathing.pathGeneration;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.localization.Pose;
|
||||
|
||||
/**
|
||||
@ -33,13 +31,13 @@ public class Point {
|
||||
* This creates a new Point with coordinate inputs and a specified coordinate system.
|
||||
*
|
||||
* @param rOrX Depending on the coordinate system specified, this is either the r or x value.
|
||||
* In polar coordinates, the r value is the distance from the origin.
|
||||
* In Cartesian coordinates, the x value is the distance left/right from the origin.
|
||||
* In polar coordinates, the r value is the distance from the origin.
|
||||
* In Cartesian coordinates, the x value is the distance left/right from the origin.
|
||||
* @param thetaOrY Depending on the coordinate system specified, this is either the theta or
|
||||
* y value.
|
||||
* In polar coordinates, the theta value is the angle from the positive x-axis.
|
||||
* Increasing theta moves in the counter-clockwise direction.
|
||||
* In Cartesian coordinates, the y value is the distance up/down from the origin.
|
||||
* y value.
|
||||
* In polar coordinates, the theta value is the angle from the positive x-axis.
|
||||
* Increasing theta moves in the counter-clockwise direction.
|
||||
* In Cartesian coordinates, the y value is the distance up/down from the origin.
|
||||
* @param identifier this specifies what coordinate system the coordinate inputs are in.
|
||||
*/
|
||||
public Point(double rOrX, double thetaOrY, int identifier) {
|
||||
@ -55,27 +53,17 @@ public class Point {
|
||||
setCoordinates(pose.getX(), pose.getY(), CARTESIAN);
|
||||
}
|
||||
|
||||
/**
|
||||
* This creates a new Point from a X and Y value.
|
||||
*
|
||||
* @param setX the X value.
|
||||
* @param setY the Y value.
|
||||
*/
|
||||
public Point(double setX, double setY) {
|
||||
setCoordinates(setX, setY, CARTESIAN);
|
||||
}
|
||||
|
||||
/**
|
||||
* This sets the coordinates of the Point using the specified coordinate system.
|
||||
*
|
||||
* @param rOrX Depending on the coordinate system specified, this is either the r or x value.
|
||||
* In polar coordinates, the r value is the distance from the origin.
|
||||
* In Cartesian coordinates, the x value is the distance left/right from the origin.
|
||||
* In polar coordinates, the r value is the distance from the origin.
|
||||
* In Cartesian coordinates, the x value is the distance left/right from the origin.
|
||||
* @param thetaOrY Depending on the coordinate system specified, this is either the theta or
|
||||
* y value.
|
||||
* In polar coordinates, the theta value is the angle from the positive x-axis.
|
||||
* Increasing theta moves in the counter-clockwise direction.
|
||||
* In Cartesian coordinates, the y value is the distance up/down from the origin.
|
||||
* y value.
|
||||
* In polar coordinates, the theta value is the angle from the positive x-axis.
|
||||
* Increasing theta moves in the counter-clockwise direction.
|
||||
* In Cartesian coordinates, the y value is the distance up/down from the origin.
|
||||
* @param identifier this specifies what coordinate system to use when setting values.
|
||||
*/
|
||||
public void setCoordinates(double rOrX, double thetaOrY, int identifier) {
|
||||
@ -90,9 +78,9 @@ public class Point {
|
||||
theta = setOtherCoordinates[1];
|
||||
break;
|
||||
default:
|
||||
if (rOrX < 0) {
|
||||
if (rOrX<0) {
|
||||
r = -rOrX;
|
||||
theta = MathFunctions.normalizeAngle(thetaOrY + Math.PI);
|
||||
theta = MathFunctions.normalizeAngle(thetaOrY+Math.PI);
|
||||
} else {
|
||||
r = rOrX;
|
||||
theta = MathFunctions.normalizeAngle(thetaOrY);
|
||||
@ -111,7 +99,7 @@ public class Point {
|
||||
* @return returns the distance between the two Points.
|
||||
*/
|
||||
public double distanceFrom(Point otherPoint) {
|
||||
return Math.sqrt(Math.pow(otherPoint.getX() - x, 2) + Math.pow(otherPoint.getY() - y, 2));
|
||||
return Math.sqrt(Math.pow(otherPoint.getX()-x, 2) + Math.pow(otherPoint.getY()-y, 2));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -122,7 +110,7 @@ public class Point {
|
||||
* @return this returns the x and y values, in that order, in an Array of doubles.
|
||||
*/
|
||||
public static double[] polarToCartesian(double r, double theta) {
|
||||
return new double[]{r * Math.cos(theta), r * Math.sin(theta)};
|
||||
return new double[] {r * Math.cos(theta), r * Math.sin(theta)};
|
||||
}
|
||||
|
||||
/**
|
||||
@ -135,17 +123,17 @@ public class Point {
|
||||
public static double[] cartesianToPolar(double x, double y) {
|
||||
if (x == 0) {
|
||||
if (y > 0) {
|
||||
return new double[]{Math.abs(y), Math.PI / 2};
|
||||
return new double[] {Math.abs(y), Math.PI/2};
|
||||
} else {
|
||||
return new double[]{Math.abs(y), (3 * Math.PI) / 2};
|
||||
return new double[] {Math.abs(y), (3 * Math.PI) / 2};
|
||||
}
|
||||
}
|
||||
double r = Math.sqrt(x * x + y * y);
|
||||
if (x < 0) return new double[]{r, Math.PI + Math.atan(y / x)};
|
||||
double r = Math.sqrt(x*x+y*y);
|
||||
if (x < 0) return new double[] {r, Math.PI+Math.atan(y/x)};
|
||||
if (y > 0) {
|
||||
return new double[]{r, Math.atan(y / x)};
|
||||
} else {
|
||||
return new double[]{r, (2 * Math.PI) + Math.atan(y / x)};
|
||||
return new double[]{r, (2*Math.PI) + Math.atan(y / x)};
|
||||
}
|
||||
}
|
||||
|
||||
@ -194,10 +182,4 @@ public class Point {
|
||||
public Point copy() {
|
||||
return new Point(getX(), getY(), CARTESIAN);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
return "(" + getX() + ", " + getY() + ")";
|
||||
}
|
||||
}
|
@ -3,7 +3,6 @@ package org.firstinspires.ftc.teamcode.pedroPathing.tuning;
|
||||
import static org.firstinspires.ftc.teamcode.PedroConstants.*;
|
||||
|
||||
import com.acmerobotics.dashboard.config.Config;
|
||||
import com.qualcomm.robotcore.hardware.DcMotorSimple;
|
||||
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.util.CustomFilteredPIDFCoefficients;
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.util.CustomPIDFCoefficients;
|
||||
@ -31,11 +30,6 @@ public class FollowerConstants {
|
||||
public static String rightFrontMotorName = FRONT_RIGHT_MOTOR;
|
||||
public static String rightRearMotorName = BACK_RIGHT_MOTOR;
|
||||
|
||||
public static DcMotorSimple.Direction leftFrontMotorDirection = FRONT_LEFT_MOTOR_DIRECTION;
|
||||
public static DcMotorSimple.Direction rightFrontMotorDirection = FRONT_RIGHT_MOTOR_DIRECTION;
|
||||
public static DcMotorSimple.Direction leftRearMotorDirection = BACK_LEFT_MOTOR_DIRECTION;
|
||||
public static DcMotorSimple.Direction rightRearMotorDirection = BACK_RIGHT_MOTOR_DIRECTION;
|
||||
|
||||
// This section is for setting the actual drive vector for the front left wheel, if the robot
|
||||
// is facing a heading of 0 radians with the wheel centered at (0,0)
|
||||
private static final double xMovement = ROBOT_SPEED_FORWARD;
|
||||
@ -46,9 +40,9 @@ public class FollowerConstants {
|
||||
|
||||
// Translational PIDF coefficients (don't use integral)
|
||||
public static CustomPIDFCoefficients translationalPIDFCoefficients = new CustomPIDFCoefficients(
|
||||
.25,
|
||||
0.1,
|
||||
0,
|
||||
0.02,
|
||||
0.01,
|
||||
0);
|
||||
|
||||
// Translational Integral
|
||||
@ -59,15 +53,15 @@ public class FollowerConstants {
|
||||
0);
|
||||
|
||||
// Feed forward constant added on to the translational PIDF
|
||||
public static double translationalPIDFFeedForward = 0.00;
|
||||
public static double translationalPIDFFeedForward = 0.015;
|
||||
|
||||
|
||||
// Heading error PIDF coefficients
|
||||
public static CustomPIDFCoefficients headingPIDFCoefficients = new CustomPIDFCoefficients(
|
||||
2,
|
||||
0,
|
||||
0.0375,
|
||||
0);
|
||||
.075,
|
||||
-.03125);
|
||||
|
||||
// Feed forward constant added on to the heading PIDF
|
||||
public static double headingPIDFFeedForward = 0.01;
|
||||
@ -75,9 +69,9 @@ public class FollowerConstants {
|
||||
|
||||
// Drive PIDF coefficients
|
||||
public static CustomFilteredPIDFCoefficients drivePIDFCoefficients = new CustomFilteredPIDFCoefficients(
|
||||
0.00235,
|
||||
0.006,
|
||||
0,
|
||||
0.00003,
|
||||
0.00001,
|
||||
0.8,
|
||||
0);
|
||||
|
||||
@ -87,7 +81,7 @@ public class FollowerConstants {
|
||||
// Kalman filter parameters for the drive error Kalman filter
|
||||
public static KalmanFilterParameters driveKalmanFilterParameters = new KalmanFilterParameters(
|
||||
6,
|
||||
3);
|
||||
1);
|
||||
|
||||
|
||||
// Mass of robot in kilograms
|
||||
@ -190,7 +184,7 @@ public class FollowerConstants {
|
||||
|
||||
|
||||
// the limit at which the heading PIDF switches between the main and secondary heading PIDFs
|
||||
public static double headingPIDFSwitch = Math.PI / 20;
|
||||
public static double headingPIDFSwitch = Math.PI/20;
|
||||
|
||||
// Secondary heading error PIDF coefficients
|
||||
public static CustomPIDFCoefficients secondaryHeadingPIDFCoefficients = new CustomPIDFCoefficients(
|
||||
|
@ -4,10 +4,6 @@ import static org.firstinspires.ftc.teamcode.pedroPathing.tuning.FollowerConstan
|
||||
import static org.firstinspires.ftc.teamcode.pedroPathing.tuning.FollowerConstants.leftRearMotorName;
|
||||
import static org.firstinspires.ftc.teamcode.pedroPathing.tuning.FollowerConstants.rightFrontMotorName;
|
||||
import static org.firstinspires.ftc.teamcode.pedroPathing.tuning.FollowerConstants.rightRearMotorName;
|
||||
import static org.firstinspires.ftc.teamcode.pedroPathing.tuning.FollowerConstants.leftFrontMotorDirection;
|
||||
import static org.firstinspires.ftc.teamcode.pedroPathing.tuning.FollowerConstants.leftRearMotorDirection;
|
||||
import static org.firstinspires.ftc.teamcode.pedroPathing.tuning.FollowerConstants.rightFrontMotorDirection;
|
||||
import static org.firstinspires.ftc.teamcode.pedroPathing.tuning.FollowerConstants.rightRearMotorDirection;
|
||||
|
||||
import com.acmerobotics.dashboard.FtcDashboard;
|
||||
import com.acmerobotics.dashboard.config.Config;
|
||||
@ -16,6 +12,7 @@ import com.qualcomm.robotcore.eventloop.opmode.Autonomous;
|
||||
import com.qualcomm.robotcore.eventloop.opmode.OpMode;
|
||||
import com.qualcomm.robotcore.hardware.DcMotor;
|
||||
import com.qualcomm.robotcore.hardware.DcMotorEx;
|
||||
import com.qualcomm.robotcore.hardware.DcMotorSimple;
|
||||
import com.qualcomm.robotcore.hardware.configuration.typecontainers.MotorConfigurationType;
|
||||
|
||||
import org.firstinspires.ftc.robotcore.external.Telemetry;
|
||||
@ -43,7 +40,7 @@ import java.util.List;
|
||||
* @version 1.0, 3/13/2024
|
||||
*/
|
||||
@Config
|
||||
@Autonomous(name = "Forward Velocity Tuner", group = "Autonomous Pathing Tuning")
|
||||
@Autonomous (name = "Forward Velocity Tuner", group = "Autonomous Pathing Tuning")
|
||||
public class ForwardVelocityTuner extends OpMode {
|
||||
private ArrayList<Double> velocities = new ArrayList<>();
|
||||
|
||||
@ -55,7 +52,7 @@ public class ForwardVelocityTuner extends OpMode {
|
||||
|
||||
private PoseUpdater poseUpdater;
|
||||
|
||||
public static double DISTANCE = 48;
|
||||
public static double DISTANCE = 40;
|
||||
public static double RECORD_NUMBER = 10;
|
||||
|
||||
private Telemetry telemetryA;
|
||||
@ -74,10 +71,10 @@ public class ForwardVelocityTuner extends OpMode {
|
||||
leftRear = hardwareMap.get(DcMotorEx.class, leftRearMotorName);
|
||||
rightRear = hardwareMap.get(DcMotorEx.class, rightRearMotorName);
|
||||
rightFront = hardwareMap.get(DcMotorEx.class, rightFrontMotorName);
|
||||
leftFront.setDirection(leftFrontMotorDirection);
|
||||
leftRear.setDirection(leftRearMotorDirection);
|
||||
rightFront.setDirection(rightFrontMotorDirection);
|
||||
rightRear.setDirection(rightRearMotorDirection);
|
||||
|
||||
// TODO: Make sure that this is the direction your motors need to be reversed in.
|
||||
leftFront.setDirection(DcMotorSimple.Direction.REVERSE);
|
||||
leftRear.setDirection(DcMotorSimple.Direction.REVERSE);
|
||||
|
||||
motors = Arrays.asList(leftFront, leftRear, rightFront, rightRear);
|
||||
|
||||
@ -125,10 +122,6 @@ public class ForwardVelocityTuner extends OpMode {
|
||||
@Override
|
||||
public void loop() {
|
||||
if (gamepad1.cross || gamepad1.a) {
|
||||
for (DcMotorEx motor : motors) {
|
||||
motor.setZeroPowerBehavior(DcMotor.ZeroPowerBehavior.BRAKE);
|
||||
motor.setPower(0);
|
||||
}
|
||||
requestOpModeStop();
|
||||
}
|
||||
|
||||
@ -146,13 +139,6 @@ public class ForwardVelocityTuner extends OpMode {
|
||||
velocities.remove(0);
|
||||
}
|
||||
} else {
|
||||
leftFront.setPower(0);
|
||||
leftRear.setPower(0);
|
||||
rightFront.setPower(0);
|
||||
rightRear.setPower(0);
|
||||
for (DcMotorEx motor : motors) {
|
||||
motor.setZeroPowerBehavior(DcMotor.ZeroPowerBehavior.BRAKE);
|
||||
}
|
||||
double average = 0;
|
||||
for (Double velocity : velocities) {
|
||||
average += velocity;
|
||||
|
@ -4,10 +4,6 @@ import static org.firstinspires.ftc.teamcode.pedroPathing.tuning.FollowerConstan
|
||||
import static org.firstinspires.ftc.teamcode.pedroPathing.tuning.FollowerConstants.leftRearMotorName;
|
||||
import static org.firstinspires.ftc.teamcode.pedroPathing.tuning.FollowerConstants.rightFrontMotorName;
|
||||
import static org.firstinspires.ftc.teamcode.pedroPathing.tuning.FollowerConstants.rightRearMotorName;
|
||||
import static org.firstinspires.ftc.teamcode.pedroPathing.tuning.FollowerConstants.leftFrontMotorDirection;
|
||||
import static org.firstinspires.ftc.teamcode.pedroPathing.tuning.FollowerConstants.leftRearMotorDirection;
|
||||
import static org.firstinspires.ftc.teamcode.pedroPathing.tuning.FollowerConstants.rightFrontMotorDirection;
|
||||
import static org.firstinspires.ftc.teamcode.pedroPathing.tuning.FollowerConstants.rightRearMotorDirection;
|
||||
|
||||
import com.acmerobotics.dashboard.FtcDashboard;
|
||||
import com.acmerobotics.dashboard.config.Config;
|
||||
@ -16,6 +12,7 @@ import com.qualcomm.robotcore.eventloop.opmode.Autonomous;
|
||||
import com.qualcomm.robotcore.eventloop.opmode.OpMode;
|
||||
import com.qualcomm.robotcore.hardware.DcMotor;
|
||||
import com.qualcomm.robotcore.hardware.DcMotorEx;
|
||||
import com.qualcomm.robotcore.hardware.DcMotorSimple;
|
||||
import com.qualcomm.robotcore.hardware.configuration.typecontainers.MotorConfigurationType;
|
||||
|
||||
import org.firstinspires.ftc.robotcore.external.Telemetry;
|
||||
@ -43,7 +40,7 @@ import java.util.List;
|
||||
* @version 1.0, 3/13/2024
|
||||
*/
|
||||
@Config
|
||||
@Autonomous(name = "Forward Zero Power Acceleration Tuner", group = "Autonomous Pathing Tuning")
|
||||
@Autonomous (name = "Forward Zero Power Acceleration Tuner", group = "Autonomous Pathing Tuning")
|
||||
public class ForwardZeroPowerAccelerationTuner extends OpMode {
|
||||
private ArrayList<Double> accelerations = new ArrayList<>();
|
||||
|
||||
@ -77,10 +74,10 @@ public class ForwardZeroPowerAccelerationTuner extends OpMode {
|
||||
leftRear = hardwareMap.get(DcMotorEx.class, leftRearMotorName);
|
||||
rightRear = hardwareMap.get(DcMotorEx.class, rightRearMotorName);
|
||||
rightFront = hardwareMap.get(DcMotorEx.class, rightFrontMotorName);
|
||||
leftFront.setDirection(leftFrontMotorDirection);
|
||||
leftRear.setDirection(leftRearMotorDirection);
|
||||
rightFront.setDirection(rightFrontMotorDirection);
|
||||
rightRear.setDirection(rightRearMotorDirection);
|
||||
|
||||
// TODO: Make sure that this is the direction your motors need to be reversed in.
|
||||
leftFront.setDirection(DcMotorSimple.Direction.REVERSE);
|
||||
leftRear.setDirection(DcMotorSimple.Direction.REVERSE);
|
||||
|
||||
motors = Arrays.asList(leftFront, leftRear, rightFront, rightRear);
|
||||
|
||||
@ -123,10 +120,6 @@ public class ForwardZeroPowerAccelerationTuner extends OpMode {
|
||||
@Override
|
||||
public void loop() {
|
||||
if (gamepad1.cross || gamepad1.a) {
|
||||
for (DcMotorEx motor : motors) {
|
||||
motor.setZeroPowerBehavior(DcMotor.ZeroPowerBehavior.BRAKE);
|
||||
motor.setPower(0);
|
||||
}
|
||||
requestOpModeStop();
|
||||
}
|
||||
|
||||
@ -156,7 +149,7 @@ public class ForwardZeroPowerAccelerationTuner extends OpMode {
|
||||
for (Double acceleration : accelerations) {
|
||||
average += acceleration;
|
||||
}
|
||||
average /= (double) accelerations.size();
|
||||
average /= (double)accelerations.size();
|
||||
|
||||
telemetryA.addData("forward zero power acceleration (deceleration):", average);
|
||||
telemetryA.update();
|
||||
|
@ -4,10 +4,6 @@ import static org.firstinspires.ftc.teamcode.pedroPathing.tuning.FollowerConstan
|
||||
import static org.firstinspires.ftc.teamcode.pedroPathing.tuning.FollowerConstants.leftRearMotorName;
|
||||
import static org.firstinspires.ftc.teamcode.pedroPathing.tuning.FollowerConstants.rightFrontMotorName;
|
||||
import static org.firstinspires.ftc.teamcode.pedroPathing.tuning.FollowerConstants.rightRearMotorName;
|
||||
import static org.firstinspires.ftc.teamcode.pedroPathing.tuning.FollowerConstants.leftFrontMotorDirection;
|
||||
import static org.firstinspires.ftc.teamcode.pedroPathing.tuning.FollowerConstants.leftRearMotorDirection;
|
||||
import static org.firstinspires.ftc.teamcode.pedroPathing.tuning.FollowerConstants.rightFrontMotorDirection;
|
||||
import static org.firstinspires.ftc.teamcode.pedroPathing.tuning.FollowerConstants.rightRearMotorDirection;
|
||||
|
||||
import com.acmerobotics.dashboard.FtcDashboard;
|
||||
import com.acmerobotics.dashboard.config.Config;
|
||||
@ -16,6 +12,7 @@ import com.qualcomm.robotcore.eventloop.opmode.Autonomous;
|
||||
import com.qualcomm.robotcore.eventloop.opmode.OpMode;
|
||||
import com.qualcomm.robotcore.hardware.DcMotor;
|
||||
import com.qualcomm.robotcore.hardware.DcMotorEx;
|
||||
import com.qualcomm.robotcore.hardware.DcMotorSimple;
|
||||
import com.qualcomm.robotcore.hardware.configuration.typecontainers.MotorConfigurationType;
|
||||
|
||||
import org.firstinspires.ftc.robotcore.external.Telemetry;
|
||||
@ -43,7 +40,7 @@ import java.util.List;
|
||||
* @version 1.0, 3/13/2024
|
||||
*/
|
||||
@Config
|
||||
@Autonomous(name = "Lateral Zero Power Acceleration Tuner", group = "Autonomous Pathing Tuning")
|
||||
@Autonomous (name = "Lateral Zero Power Acceleration Tuner", group = "Autonomous Pathing Tuning")
|
||||
public class LateralZeroPowerAccelerationTuner extends OpMode {
|
||||
private ArrayList<Double> accelerations = new ArrayList<>();
|
||||
|
||||
@ -55,7 +52,7 @@ public class LateralZeroPowerAccelerationTuner extends OpMode {
|
||||
|
||||
private PoseUpdater poseUpdater;
|
||||
|
||||
public static double VELOCITY = 30;
|
||||
public static double VELOCITY = 50;
|
||||
|
||||
private double previousVelocity;
|
||||
|
||||
@ -77,10 +74,10 @@ public class LateralZeroPowerAccelerationTuner extends OpMode {
|
||||
leftRear = hardwareMap.get(DcMotorEx.class, leftRearMotorName);
|
||||
rightRear = hardwareMap.get(DcMotorEx.class, rightRearMotorName);
|
||||
rightFront = hardwareMap.get(DcMotorEx.class, rightFrontMotorName);
|
||||
leftFront.setDirection(leftFrontMotorDirection);
|
||||
leftRear.setDirection(leftRearMotorDirection);
|
||||
rightFront.setDirection(rightFrontMotorDirection);
|
||||
rightRear.setDirection(rightRearMotorDirection);
|
||||
|
||||
// TODO: Make sure that this is the direction your motors need to be reversed in.
|
||||
leftFront.setDirection(DcMotorSimple.Direction.REVERSE);
|
||||
leftRear.setDirection(DcMotorSimple.Direction.REVERSE);
|
||||
|
||||
motors = Arrays.asList(leftFront, leftRear, rightFront, rightRear);
|
||||
|
||||
@ -122,16 +119,19 @@ public class LateralZeroPowerAccelerationTuner extends OpMode {
|
||||
*/
|
||||
@Override
|
||||
public void loop() {
|
||||
|
||||
telemetry.addData("x",poseUpdater.getPose().getX());
|
||||
telemetry.addData("y",poseUpdater.getPose().getY());
|
||||
telemetry.addData("heading",poseUpdater.getPose().getHeading());
|
||||
telemetry.addData("velo mag", poseUpdater.getVelocity().getMagnitude());
|
||||
telemetry.addData("velo theta", poseUpdater.getVelocity().getTheta());
|
||||
|
||||
if (gamepad1.cross || gamepad1.a) {
|
||||
for (DcMotorEx motor : motors) {
|
||||
motor.setZeroPowerBehavior(DcMotor.ZeroPowerBehavior.BRAKE);
|
||||
motor.setPower(0);
|
||||
}
|
||||
requestOpModeStop();
|
||||
}
|
||||
|
||||
poseUpdater.update();
|
||||
Vector heading = new Vector(1.0, poseUpdater.getPose().getHeading() - Math.PI / 2);
|
||||
Vector heading = new Vector(1.0, poseUpdater.getPose().getHeading() - Math.PI/2);
|
||||
if (!end) {
|
||||
if (!stopping) {
|
||||
if (MathFunctions.dotProduct(poseUpdater.getVelocity(), heading) > VELOCITY) {
|
||||
@ -156,7 +156,7 @@ public class LateralZeroPowerAccelerationTuner extends OpMode {
|
||||
for (Double acceleration : accelerations) {
|
||||
average += acceleration;
|
||||
}
|
||||
average /= (double) accelerations.size();
|
||||
average /= (double)accelerations.size();
|
||||
|
||||
telemetryA.addData("lateral zero power acceleration (deceleration):", average);
|
||||
telemetryA.update();
|
||||
|
@ -4,10 +4,6 @@ import static org.firstinspires.ftc.teamcode.pedroPathing.tuning.FollowerConstan
|
||||
import static org.firstinspires.ftc.teamcode.pedroPathing.tuning.FollowerConstants.leftRearMotorName;
|
||||
import static org.firstinspires.ftc.teamcode.pedroPathing.tuning.FollowerConstants.rightFrontMotorName;
|
||||
import static org.firstinspires.ftc.teamcode.pedroPathing.tuning.FollowerConstants.rightRearMotorName;
|
||||
import static org.firstinspires.ftc.teamcode.pedroPathing.tuning.FollowerConstants.leftFrontMotorDirection;
|
||||
import static org.firstinspires.ftc.teamcode.pedroPathing.tuning.FollowerConstants.leftRearMotorDirection;
|
||||
import static org.firstinspires.ftc.teamcode.pedroPathing.tuning.FollowerConstants.rightFrontMotorDirection;
|
||||
import static org.firstinspires.ftc.teamcode.pedroPathing.tuning.FollowerConstants.rightRearMotorDirection;
|
||||
|
||||
import com.acmerobotics.dashboard.FtcDashboard;
|
||||
import com.acmerobotics.dashboard.config.Config;
|
||||
@ -16,6 +12,7 @@ import com.qualcomm.robotcore.eventloop.opmode.Autonomous;
|
||||
import com.qualcomm.robotcore.eventloop.opmode.OpMode;
|
||||
import com.qualcomm.robotcore.hardware.DcMotor;
|
||||
import com.qualcomm.robotcore.hardware.DcMotorEx;
|
||||
import com.qualcomm.robotcore.hardware.DcMotorSimple;
|
||||
import com.qualcomm.robotcore.hardware.configuration.typecontainers.MotorConfigurationType;
|
||||
|
||||
import org.firstinspires.ftc.robotcore.external.Telemetry;
|
||||
@ -43,7 +40,7 @@ import java.util.List;
|
||||
* @version 1.0, 3/13/2024
|
||||
*/
|
||||
@Config
|
||||
@Autonomous(name = "Strafe Velocity Tuner", group = "Autonomous Pathing Tuning")
|
||||
@Autonomous (name = "Strafe Velocity Tuner", group = "Autonomous Pathing Tuning")
|
||||
public class StrafeVelocityTuner extends OpMode {
|
||||
private ArrayList<Double> velocities = new ArrayList<>();
|
||||
|
||||
@ -55,7 +52,7 @@ public class StrafeVelocityTuner extends OpMode {
|
||||
|
||||
private PoseUpdater poseUpdater;
|
||||
|
||||
public static double DISTANCE = 48;
|
||||
public static double DISTANCE = 40;
|
||||
public static double RECORD_NUMBER = 10;
|
||||
|
||||
private Telemetry telemetryA;
|
||||
@ -74,10 +71,10 @@ public class StrafeVelocityTuner extends OpMode {
|
||||
leftRear = hardwareMap.get(DcMotorEx.class, leftRearMotorName);
|
||||
rightRear = hardwareMap.get(DcMotorEx.class, rightRearMotorName);
|
||||
rightFront = hardwareMap.get(DcMotorEx.class, rightFrontMotorName);
|
||||
leftFront.setDirection(leftFrontMotorDirection);
|
||||
leftRear.setDirection(leftRearMotorDirection);
|
||||
rightFront.setDirection(rightFrontMotorDirection);
|
||||
rightRear.setDirection(rightRearMotorDirection);
|
||||
|
||||
// TODO: Make sure that this is the direction your motors need to be reversed in.
|
||||
leftFront.setDirection(DcMotorSimple.Direction.REVERSE);
|
||||
leftRear.setDirection(DcMotorSimple.Direction.REVERSE);
|
||||
|
||||
motors = Arrays.asList(leftFront, leftRear, rightFront, rightRear);
|
||||
|
||||
@ -123,10 +120,6 @@ public class StrafeVelocityTuner extends OpMode {
|
||||
@Override
|
||||
public void loop() {
|
||||
if (gamepad1.cross || gamepad1.a) {
|
||||
for (DcMotorEx motor : motors) {
|
||||
motor.setZeroPowerBehavior(DcMotor.ZeroPowerBehavior.BRAKE);
|
||||
motor.setPower(0);
|
||||
}
|
||||
requestOpModeStop();
|
||||
}
|
||||
|
||||
@ -139,18 +132,11 @@ public class StrafeVelocityTuner extends OpMode {
|
||||
motor.setPower(0);
|
||||
}
|
||||
} else {
|
||||
double currentVelocity = Math.abs(MathFunctions.dotProduct(poseUpdater.getVelocity(), new Vector(1, Math.PI / 2)));
|
||||
double currentVelocity = Math.abs(MathFunctions.dotProduct(poseUpdater.getVelocity(), new Vector(1, Math.PI/2)));
|
||||
velocities.add(currentVelocity);
|
||||
velocities.remove(0);
|
||||
}
|
||||
} else {
|
||||
leftFront.setPower(0);
|
||||
leftRear.setPower(0);
|
||||
rightFront.setPower(0);
|
||||
rightRear.setPower(0);
|
||||
for (DcMotorEx motor : motors) {
|
||||
motor.setZeroPowerBehavior(DcMotor.ZeroPowerBehavior.BRAKE);
|
||||
}
|
||||
double average = 0;
|
||||
for (Double velocity : velocities) {
|
||||
average += velocity;
|
||||
|
@ -20,14 +20,11 @@ import org.firstinspires.ftc.teamcode.pedroPathing.pathGeneration.Vector;
|
||||
* @version 1.0, 4/22/2024
|
||||
*/
|
||||
public class Drawing {
|
||||
public static final double ROBOT_RADIUS = 9;
|
||||
|
||||
private static TelemetryPacket packet;
|
||||
|
||||
/**
|
||||
* This draws everything that will be used in the Follower's telemetryDebug() method. This takes
|
||||
* a Follower as an input, so an instance of the DashbaordDrawingHandler class is not needed.
|
||||
*
|
||||
* @param follower
|
||||
*/
|
||||
public static void drawDebug(Follower follower) {
|
||||
@ -38,7 +35,6 @@ public class Drawing {
|
||||
}
|
||||
drawPoseHistory(follower.getDashboardPoseTracker(), "#4CAF50");
|
||||
drawRobot(follower.getPose(), "#4CAF50");
|
||||
|
||||
sendPacket();
|
||||
}
|
||||
|
||||
@ -118,10 +114,12 @@ public class Drawing {
|
||||
* @param t the Point to draw at
|
||||
*/
|
||||
public static void drawRobotOnCanvas(Canvas c, Point t) {
|
||||
final double ROBOT_RADIUS = 9;
|
||||
|
||||
c.setStrokeWidth(1);
|
||||
c.strokeCircle(t.getX(), t.getY(), ROBOT_RADIUS);
|
||||
|
||||
Vector halfv = new Vector(0.5 * ROBOT_RADIUS, t.getTheta());
|
||||
Vector halfv = new Vector(0.5*ROBOT_RADIUS, t.getTheta());
|
||||
Vector p1 = MathFunctions.addVectors(halfv, new Vector(t.getR(), t.getTheta()));
|
||||
Vector p2 = MathFunctions.addVectors(p1, halfv);
|
||||
c.strokeLine(p1.getXComponent(), p1.getYComponent(), p2.getXComponent(), p2.getYComponent());
|
||||
@ -135,6 +133,8 @@ public class Drawing {
|
||||
* @param t the Pose to draw at
|
||||
*/
|
||||
public static void drawRobotOnCanvas(Canvas c, Pose t) {
|
||||
final double ROBOT_RADIUS = 9;
|
||||
|
||||
c.strokeCircle(t.getX(), t.getY(), ROBOT_RADIUS);
|
||||
Vector v = t.getHeadingVector();
|
||||
v.setMagnitude(v.getMagnitude() * ROBOT_RADIUS);
|
||||
|
@ -1,136 +0,0 @@
|
||||
package org.firstinspires.ftc.teamcode.states;
|
||||
|
||||
import com.acmerobotics.dashboard.FtcDashboard;
|
||||
import com.acmerobotics.dashboard.telemetry.MultipleTelemetry;
|
||||
import com.qualcomm.robotcore.eventloop.opmode.Autonomous;
|
||||
import com.qualcomm.robotcore.eventloop.opmode.OpMode;
|
||||
|
||||
import org.firstinspires.ftc.robotcore.external.Telemetry;
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.follower.Follower;
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.localization.Pose;
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.pathGeneration.BezierCurve;
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.pathGeneration.BezierLine;
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.pathGeneration.PathChain;
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.pathGeneration.Point;
|
||||
|
||||
@Autonomous(name = "Blue Basket Auto States", group = "Competition")
|
||||
public class BlueBasketAutoStates extends OpMode {
|
||||
private Telemetry telemetryA;
|
||||
|
||||
private Follower follower;
|
||||
|
||||
private PathChain path;
|
||||
|
||||
private final Pose startPose = new Pose(11.25, 95.75);
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
follower = new Follower(hardwareMap);
|
||||
|
||||
follower.setMaxPower(.45);
|
||||
|
||||
follower.setStartingPose(startPose);
|
||||
|
||||
path = follower.pathBuilder()
|
||||
.addPath(
|
||||
// Line 1
|
||||
new BezierLine(
|
||||
new Point(11.250, 95.750, Point.CARTESIAN),
|
||||
new Point(37.000, 108.000, Point.CARTESIAN)
|
||||
)
|
||||
)
|
||||
.setConstantHeadingInterpolation(Math.toRadians(0))
|
||||
.addPath(
|
||||
// Line 2
|
||||
new BezierCurve(
|
||||
new Point(37.000, 108.000, Point.CARTESIAN),
|
||||
new Point(73.286, 111.536, Point.CARTESIAN),
|
||||
new Point(67.821, 120.536, Point.CARTESIAN)
|
||||
)
|
||||
)
|
||||
.setConstantHeadingInterpolation(Math.toRadians(0))
|
||||
.addPath(
|
||||
// Line 3
|
||||
new BezierLine(
|
||||
new Point(67.821, 120.536, Point.CARTESIAN),
|
||||
new Point(28.000, 121.500, Point.CARTESIAN)
|
||||
)
|
||||
)
|
||||
.setConstantHeadingInterpolation(Math.toRadians(0))
|
||||
.addPath(
|
||||
// Line 4
|
||||
new BezierLine(
|
||||
new Point(28.000, 121.500, Point.CARTESIAN),
|
||||
new Point(18.000, 130.179, Point.CARTESIAN)
|
||||
)
|
||||
)
|
||||
.setConstantHeadingInterpolation(Math.toRadians(0))
|
||||
.addPath(
|
||||
// Line 5
|
||||
new BezierCurve(
|
||||
new Point(18.000, 130.179, Point.CARTESIAN),
|
||||
new Point(59.000, 102.500, Point.CARTESIAN),
|
||||
new Point(68.700, 130.500, Point.CARTESIAN)
|
||||
)
|
||||
)
|
||||
.setConstantHeadingInterpolation(Math.toRadians(0))
|
||||
.addPath(
|
||||
// Line 6
|
||||
new BezierLine(
|
||||
new Point(68.700, 130.500, Point.CARTESIAN),
|
||||
new Point(18.000, 130.339, Point.CARTESIAN)
|
||||
)
|
||||
)
|
||||
.setConstantHeadingInterpolation(Math.toRadians(0))
|
||||
.addPath(
|
||||
// Line 7
|
||||
new BezierCurve(
|
||||
new Point(18.000, 130.339, Point.CARTESIAN),
|
||||
new Point(49.018, 121.179, Point.CARTESIAN),
|
||||
new Point(63.804, 135.321, Point.CARTESIAN)
|
||||
)
|
||||
)
|
||||
.setConstantHeadingInterpolation(Math.toRadians(0))
|
||||
.addPath(
|
||||
// Line 8
|
||||
new BezierLine(
|
||||
new Point(63.804, 135.321, Point.CARTESIAN),
|
||||
new Point(53.036, 135.161, Point.CARTESIAN)
|
||||
)
|
||||
)
|
||||
.setConstantHeadingInterpolation(Math.toRadians(0))
|
||||
.addPath(
|
||||
// Line 9
|
||||
new BezierLine(
|
||||
new Point(53.036, 135.161, Point.CARTESIAN),
|
||||
new Point(18.643, 135.000, Point.CARTESIAN)
|
||||
)
|
||||
)
|
||||
.setConstantHeadingInterpolation(Math.toRadians(0))
|
||||
.addPath(
|
||||
// Line 10
|
||||
new BezierLine(
|
||||
new Point(18.643, 135.000, Point.CARTESIAN),
|
||||
new Point(72.300, 97.400, Point.CARTESIAN)
|
||||
)
|
||||
)
|
||||
.addPath(
|
||||
// Line 11
|
||||
new BezierLine(
|
||||
new Point(18.643, 135.000, Point.CARTESIAN),
|
||||
new Point(83.250, 95.464, Point.CARTESIAN)
|
||||
)
|
||||
)
|
||||
.setLinearHeadingInterpolation(Math.toRadians(0), Math.toRadians(270)).build();
|
||||
follower.followPath(path);
|
||||
|
||||
telemetryA = new MultipleTelemetry(this.telemetry, FtcDashboard.getInstance().getTelemetry());
|
||||
telemetryA.update();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loop() {
|
||||
follower.update();
|
||||
follower.telemetryDebug(telemetryA);
|
||||
}
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
package org.firstinspires.ftc.teamcode.states;
|
||||
|
||||
public class FieldStates {
|
||||
|
||||
public enum FieldLocation {
|
||||
BUCKET, SUBMARINE, FLOATING, TRAVELING
|
||||
}
|
||||
|
||||
private FieldLocation fieldLocation;
|
||||
|
||||
public FieldLocation getFieldLocation() {
|
||||
return fieldLocation;
|
||||
}
|
||||
|
||||
public void setFieldLocation(FieldLocation fieldLocation) {
|
||||
this.fieldLocation = fieldLocation;
|
||||
}
|
||||
}
|
@ -1,83 +0,0 @@
|
||||
package org.firstinspires.ftc.teamcode.subsystem;
|
||||
|
||||
import static org.firstinspires.ftc.teamcode.PedroConstants.ARM_SERVO;
|
||||
import static org.firstinspires.ftc.teamcode.configs.RobotConstants.armBucket;
|
||||
import static org.firstinspires.ftc.teamcode.configs.RobotConstants.armFloor;
|
||||
import static org.firstinspires.ftc.teamcode.configs.RobotConstants.armGrabBlueberrySkyhook;
|
||||
import static org.firstinspires.ftc.teamcode.configs.RobotConstants.armHangBlueberrySkyhook;
|
||||
import static org.firstinspires.ftc.teamcode.configs.RobotConstants.armInit;
|
||||
import static org.firstinspires.ftc.teamcode.configs.RobotConstants.armPark;
|
||||
import static org.firstinspires.ftc.teamcode.configs.RobotConstants.armReverseBucket;
|
||||
|
||||
import com.qualcomm.robotcore.hardware.HardwareMap;
|
||||
import com.qualcomm.robotcore.hardware.ServoImplEx;
|
||||
|
||||
public class ArmSubsystem {
|
||||
|
||||
public enum ArmState {
|
||||
PARK, FLOOR, BUCKET, SUBMARINE, GRAB_BLUEBERRY_SKYHOOK, HANG_BLUEBERRY_SKYHOOK, INIT, REVERE_BUCKET
|
||||
}
|
||||
|
||||
private ServoImplEx arm;
|
||||
private ArmState state;
|
||||
|
||||
public ArmSubsystem(HardwareMap hardwareMap) {
|
||||
this.arm = hardwareMap.get(ServoImplEx.class, ARM_SERVO);
|
||||
}
|
||||
public void grabBlueberrySkyhook(){
|
||||
setState(ArmState.GRAB_BLUEBERRY_SKYHOOK);
|
||||
arm.setPosition(armGrabBlueberrySkyhook);
|
||||
}
|
||||
public void hangBlueberrySkyhook(){
|
||||
setState(ArmState.HANG_BLUEBERRY_SKYHOOK);
|
||||
arm.setPosition(armHangBlueberrySkyhook);
|
||||
}
|
||||
public void toReverseBucket(){
|
||||
arm.setPosition(armReverseBucket);
|
||||
setState(ArmState.REVERE_BUCKET);
|
||||
}
|
||||
public void toParkPosition() {
|
||||
arm.setPosition(armPark);
|
||||
setState(ArmState.PARK);
|
||||
}
|
||||
|
||||
public void toFloorPosition() {
|
||||
arm.setPosition(armFloor);
|
||||
setState(ArmState.FLOOR);
|
||||
}
|
||||
|
||||
public void toBucketPosition() {
|
||||
arm.setPosition(armBucket);
|
||||
setState(ArmState.BUCKET);
|
||||
}
|
||||
public void toInitPosition(){
|
||||
arm.setPosition(armInit);
|
||||
setState(ArmState.INIT);
|
||||
}
|
||||
|
||||
public void setState(ArmState armState) {
|
||||
this.state = armState;
|
||||
}
|
||||
|
||||
public ArmState getState() {
|
||||
return this.state;
|
||||
}
|
||||
|
||||
public void initTeleOp() {
|
||||
arm.resetDeviceConfigurationForOpMode();
|
||||
toParkPosition();
|
||||
}
|
||||
public void initAuto(){
|
||||
arm.resetDeviceConfigurationForOpMode();
|
||||
toInitPosition();
|
||||
}
|
||||
|
||||
public double getPosition() {
|
||||
return this.arm.getPosition();
|
||||
}
|
||||
|
||||
public void setPosition(double position) {
|
||||
this.arm.setPosition(position);
|
||||
}
|
||||
|
||||
}
|
@ -1,91 +0,0 @@
|
||||
package org.firstinspires.ftc.teamcode.subsystem;
|
||||
|
||||
import static org.firstinspires.ftc.teamcode.PedroConstants.CLAW_NAME;
|
||||
import static org.firstinspires.ftc.teamcode.PedroConstants.THUMB_SERVO;
|
||||
import static org.firstinspires.ftc.teamcode.configs.RobotConstants.clawClose;
|
||||
import static org.firstinspires.ftc.teamcode.configs.RobotConstants.clawOpen;
|
||||
import static org.firstinspires.ftc.teamcode.configs.RobotConstants.grabBlueberry;
|
||||
|
||||
import com.qualcomm.robotcore.hardware.HardwareMap;
|
||||
import com.qualcomm.robotcore.hardware.Servo;
|
||||
|
||||
public class ClawSubsystem {
|
||||
|
||||
public enum ClawState {
|
||||
CLOSED, OPEN, GRAB_BLUEBERRY
|
||||
}
|
||||
|
||||
public enum ThumbState {
|
||||
DOWN, UP, AWAY
|
||||
}
|
||||
|
||||
private Servo claw;
|
||||
private Servo thumb;
|
||||
private ClawState state;
|
||||
private ThumbState tState;
|
||||
|
||||
public ClawSubsystem(HardwareMap hardwareMap) {
|
||||
claw = hardwareMap.get(Servo.class, CLAW_NAME);
|
||||
thumb = hardwareMap.get(Servo.class, THUMB_SERVO);
|
||||
}
|
||||
public void grabBlueberry(){
|
||||
claw.setPosition(grabBlueberry);
|
||||
state = ClawState.GRAB_BLUEBERRY;
|
||||
}
|
||||
public void closeClaw() {
|
||||
claw.setPosition(clawClose);
|
||||
|
||||
state = ClawState.CLOSED;
|
||||
}
|
||||
|
||||
public void openClaw() {
|
||||
claw.setPosition(clawOpen);
|
||||
|
||||
state = ClawState.OPEN;
|
||||
}
|
||||
|
||||
public ClawState getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public ThumbState getTState() {
|
||||
return tState;
|
||||
}
|
||||
|
||||
public void switchState() {
|
||||
if (state == ClawState.CLOSED) {
|
||||
openClaw();
|
||||
} else if (state == ClawState.OPEN) {
|
||||
closeClaw();
|
||||
}
|
||||
}
|
||||
|
||||
public void switchTState() {
|
||||
if (tState == ThumbState.UP) {
|
||||
thumbDown();
|
||||
} else if (tState == ThumbState.DOWN) {
|
||||
thumbUp();
|
||||
}
|
||||
}
|
||||
|
||||
public void init() {
|
||||
closeClaw();
|
||||
thumbDown();
|
||||
}
|
||||
|
||||
public void thumbUp() {
|
||||
thumb.setPosition(0.5);
|
||||
tState = ThumbState.UP;
|
||||
}
|
||||
|
||||
public void thumbDown() {
|
||||
thumb.setPosition(0.00);
|
||||
tState = ThumbState.DOWN;
|
||||
}
|
||||
|
||||
public void thumbOutOfTheWay() {
|
||||
thumb.setPosition(0.95);
|
||||
tState = ThumbState.AWAY;
|
||||
}
|
||||
|
||||
}
|
@ -1,159 +0,0 @@
|
||||
package org.firstinspires.ftc.teamcode.subsystem;
|
||||
|
||||
import static org.firstinspires.ftc.teamcode.PedroConstants.LIFT_SLIDE_LEFT_MOTOR;
|
||||
import static org.firstinspires.ftc.teamcode.PedroConstants.LIFT_SLIDE_RIGHT_MOTOR;
|
||||
import static org.firstinspires.ftc.teamcode.configs.RobotConstants.backwardBucketDrop;
|
||||
import static org.firstinspires.ftc.teamcode.configs.RobotConstants.liftToHighBucketPos;
|
||||
import static org.firstinspires.ftc.teamcode.configs.RobotConstants.liftToLowBucketPos;
|
||||
import static org.firstinspires.ftc.teamcode.configs.RobotConstants.slideBelowFloor;
|
||||
import static org.firstinspires.ftc.teamcode.configs.RobotConstants.slideHangBlueberrySkyhook;
|
||||
|
||||
import com.qualcomm.robotcore.hardware.DcMotor;
|
||||
import com.qualcomm.robotcore.hardware.DcMotorEx;
|
||||
import com.qualcomm.robotcore.hardware.DcMotorSimple;
|
||||
import com.qualcomm.robotcore.hardware.HardwareMap;
|
||||
import com.qualcomm.robotcore.util.ElapsedTime;
|
||||
|
||||
public class DualMotorSliderSubsystem {
|
||||
|
||||
/*
|
||||
liftSlideLeft - Left Motor for Dual Linear Slide as a DcMotorEx object
|
||||
Currently, the value of (liftSlideLeft) is null because we haven't assigned a value (object) to it yet.
|
||||
It expects an object of type "DcMotorEx".
|
||||
*/
|
||||
private DcMotorEx liftSlideLeft;
|
||||
|
||||
/*
|
||||
liftSlideRight - Right Motor for Dual Linear Slide as a DcMotorEx object
|
||||
Currently, the value of (liftSlideRight) is null because we haven't assigned a value (object) to it yet.
|
||||
It expects an object of type "DcMotorEx".
|
||||
*/
|
||||
private DcMotorEx liftSlideRight;
|
||||
|
||||
/*
|
||||
targetPosition - Variable that holds target position of slides.
|
||||
*/
|
||||
private int targetPosition = 0;
|
||||
|
||||
/*
|
||||
getTargetPosition/setTargetPosition - Best practice to "hide" (private) targetPosition and,
|
||||
instead, use a "setter" to set the target position value or
|
||||
a "getter" to get the target position value.
|
||||
*/
|
||||
public void setTargetPosition(int value) {
|
||||
targetPosition = value;
|
||||
}
|
||||
private int getTargetPosition() { return targetPosition; }
|
||||
|
||||
/*
|
||||
PID - Proportional/Integral/Derivative Values
|
||||
|
||||
For a dual motor linear slide, we only tune the P - Proportion.
|
||||
The Proportion variable (kp) answers the question "how fast do we want to get to our destination?"
|
||||
|
||||
It's the only value we set because the variable ki and kd deal with how to handle when we're off the path.
|
||||
Since we're going straight, we don't need to worry about.
|
||||
*/
|
||||
public final static double kp = 0.0015, ki = 0, kd = 0;
|
||||
|
||||
/*
|
||||
lastError/integralSum/timer - These 3 variables are placeholders in determining how much
|
||||
power to send to both motors.
|
||||
*/
|
||||
private double lastError = 0;
|
||||
private double integralSum = 0;
|
||||
private ElapsedTime timer = new ElapsedTime();
|
||||
|
||||
public DualMotorSliderSubsystem(HardwareMap hardwareMap) {
|
||||
/*
|
||||
liftSlideLeft/liftSlideRight - Now, we are assigning a value of DcMotorEx to each variable
|
||||
|
||||
We "assign" the object DcMotorEx to liftSlideLeft and liftSlideRight and "link them" to the
|
||||
driver hub configuration name that matches the motor on the slide.
|
||||
*/
|
||||
liftSlideLeft = hardwareMap.get(DcMotorEx.class, LIFT_SLIDE_LEFT_MOTOR);
|
||||
liftSlideRight = hardwareMap.get(DcMotorEx.class, LIFT_SLIDE_RIGHT_MOTOR);
|
||||
}
|
||||
public int getCurrentPosition(){
|
||||
return liftSlideLeft.getCurrentPosition();
|
||||
}
|
||||
public void init() {
|
||||
/*
|
||||
Initialize the motors with the following settings (assuming slide is at the very bottom position):
|
||||
|
||||
- Reset the encoders to be zero
|
||||
- When the motor stops moving (zero power), brake. This means we can't move the motors, not even gravity.
|
||||
- Sets the motor to run without the encoder. This doesn't mean we won't use the encoder values (because we will).
|
||||
It just means to not FULLY depend on them, we will just prefer to use motor power instead.
|
||||
*/
|
||||
liftSlideLeft.setMode(DcMotor.RunMode.STOP_AND_RESET_ENCODER);
|
||||
liftSlideLeft.setZeroPowerBehavior(DcMotor.ZeroPowerBehavior.BRAKE);
|
||||
liftSlideLeft.setMode(DcMotor.RunMode.RUN_WITHOUT_ENCODER);
|
||||
liftSlideLeft.setDirection(DcMotorSimple.Direction.REVERSE);
|
||||
liftSlideRight.setDirection(DcMotorSimple.Direction.REVERSE);
|
||||
liftSlideRight.setMode(DcMotor.RunMode.STOP_AND_RESET_ENCODER);
|
||||
liftSlideRight.setZeroPowerBehavior(DcMotor.ZeroPowerBehavior.BRAKE);
|
||||
liftSlideRight.setMode(DcMotor.RunMode.RUN_WITHOUT_ENCODER);
|
||||
}
|
||||
|
||||
/*
|
||||
To calculate power, we send the targetPosition value (how high we want the slider motors to
|
||||
be based on motor 'ticks') to calculatePower function.
|
||||
|
||||
For every loop that occurs, it will constantly calculate power. So long as we're far away from
|
||||
our "target" position, we will get as much power as possible. The closer we get, the lower the
|
||||
power we will receive.
|
||||
*/
|
||||
public void update() {
|
||||
double power = calculatePower();
|
||||
liftSlideLeft.setPower(power);
|
||||
liftSlideRight.setPower(power);
|
||||
}
|
||||
|
||||
/*
|
||||
Calculating power - To calculate the power, we determine the proportion, derivative and
|
||||
integral of our closed loop system.
|
||||
|
||||
For more information, please visit:
|
||||
- Introduction to Closed Loop System:
|
||||
- https://www.ctrlaltftc.com/introduction-to-closed-loop-control
|
||||
- The PID controller:
|
||||
- https://www.ctrlaltftc.com/the-pid-controller
|
||||
*/
|
||||
private double calculatePower() {
|
||||
double error = getTargetPosition() - liftSlideLeft.getCurrentPosition();
|
||||
integralSum += error * timer.seconds();
|
||||
double derivative = (error - lastError) / timer.seconds();
|
||||
lastError = error;
|
||||
timer.reset();
|
||||
return (error * kp) + (derivative * kd) + (integralSum * ki);
|
||||
}
|
||||
|
||||
public void toLowBucketPosition() {
|
||||
setTargetPosition(liftToLowBucketPos);
|
||||
}
|
||||
|
||||
public void toHighBucketPosition() {
|
||||
setTargetPosition(liftToHighBucketPos);
|
||||
}
|
||||
|
||||
public void toFixedPosition(int value) {
|
||||
setTargetPosition(value);
|
||||
}
|
||||
public void toHangHeight(){
|
||||
setTargetPosition(slideHangBlueberrySkyhook);
|
||||
|
||||
}
|
||||
public void toHangBelowFloor(){
|
||||
setTargetPosition(slideBelowFloor);
|
||||
|
||||
}
|
||||
|
||||
public int getFixedPosition() {
|
||||
return liftSlideLeft.getCurrentPosition();
|
||||
}
|
||||
|
||||
public void toFloorPosition(){setTargetPosition(0);}
|
||||
public void toHighBucketReverseDrop(){setTargetPosition(backwardBucketDrop);}
|
||||
|
||||
}
|
@ -1,60 +0,0 @@
|
||||
package org.firstinspires.ftc.teamcode.subsystem;
|
||||
|
||||
import static org.firstinspires.ftc.teamcode.PedroConstants.HOOK;
|
||||
import static org.firstinspires.ftc.teamcode.PedroConstants.LIFT_SLIDE_LEFT_MOTOR;
|
||||
import static org.firstinspires.ftc.teamcode.PedroConstants.LIFT_SLIDE_RIGHT_MOTOR;
|
||||
|
||||
import com.qualcomm.robotcore.hardware.DcMotor;
|
||||
import com.qualcomm.robotcore.hardware.DcMotorEx;
|
||||
import com.qualcomm.robotcore.hardware.DcMotorSimple;
|
||||
import com.qualcomm.robotcore.hardware.HardwareMap;
|
||||
import static org.firstinspires.ftc.teamcode.configs.RobotConstants.toBar;
|
||||
import static org.firstinspires.ftc.teamcode.configs.RobotConstants.toFloor;
|
||||
|
||||
public class HangMotorSubsystem {
|
||||
private DcMotorEx hang;
|
||||
|
||||
public HangMotorSubsystem(HardwareMap hardwareMap) {
|
||||
|
||||
hang = hardwareMap.get(DcMotorEx.class, HOOK);
|
||||
|
||||
|
||||
}
|
||||
|
||||
public int getCurrentPosition(){
|
||||
int Return = hang.getCurrentPosition();
|
||||
return Return;
|
||||
}
|
||||
public void init(){
|
||||
hang.setMode(DcMotor.RunMode.STOP_AND_RESET_ENCODER);
|
||||
hang.setDirection(DcMotorSimple.Direction.FORWARD);
|
||||
hang.setZeroPowerBehavior(DcMotor.ZeroPowerBehavior.BRAKE);
|
||||
hang.setMode(DcMotor.RunMode.RUN_USING_ENCODER);
|
||||
|
||||
}
|
||||
public void hangRobot(){
|
||||
hang.setTargetPosition(toBar);
|
||||
|
||||
}
|
||||
public void robotToFloor(){
|
||||
hang.setTargetPosition(toFloor);
|
||||
}
|
||||
public void disableMotor(){
|
||||
hang.setPower(0);
|
||||
hang.setMotorDisable();
|
||||
|
||||
}
|
||||
public void setPower(double power){
|
||||
hang.setPower(power);
|
||||
}
|
||||
public void stopMotor(){
|
||||
hang.setPower(0);
|
||||
|
||||
|
||||
}
|
||||
public void toHangPosition(int Position){
|
||||
//write in limits for protection
|
||||
hang.setPower(Position);
|
||||
}
|
||||
|
||||
}
|
@ -1,141 +0,0 @@
|
||||
package org.firstinspires.ftc.teamcode.subsystem;
|
||||
|
||||
/* Copyright (c) 2021 FIRST. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted (subject to the limitations in the disclaimer below) 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 nor the names of its contributors may be used to endorse or
|
||||
* promote products derived from this software without specific prior written permission.
|
||||
*
|
||||
* NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS
|
||||
* LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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.
|
||||
*/
|
||||
|
||||
import com.acmerobotics.roadrunner.SequentialAction;
|
||||
import com.acmerobotics.roadrunner.SleepAction;
|
||||
import com.acmerobotics.roadrunner.ftc.Actions;
|
||||
import com.qualcomm.robotcore.eventloop.opmode.LinearOpMode;
|
||||
import com.qualcomm.robotcore.eventloop.opmode.TeleOp;
|
||||
import com.qualcomm.robotcore.hardware.Gamepad;
|
||||
import com.qualcomm.robotcore.util.ElapsedTime;
|
||||
|
||||
import org.firstinspires.ftc.teamcode.subsystem.ArmSubsystem;
|
||||
import org.firstinspires.ftc.teamcode.subsystem.DualMotorSliderSubsystem;
|
||||
import org.firstinspires.ftc.teamcode.subsystem.WristSubsystem;
|
||||
import org.firstinspires.ftc.teamcode.subsystem.ClawSubsystem;
|
||||
|
||||
|
||||
@TeleOp(name = "Lift Wrist Arm Test", group = "Debug")
|
||||
public class LiftArmWrist extends LinearOpMode {
|
||||
|
||||
private final ElapsedTime runtime = new ElapsedTime();
|
||||
|
||||
@Override
|
||||
public void runOpMode() {
|
||||
|
||||
/*
|
||||
* Instantiate Lift
|
||||
*/
|
||||
DualMotorSliderSubsystem lift = new DualMotorSliderSubsystem(hardwareMap);
|
||||
WristSubsystem wrist = new WristSubsystem(hardwareMap);
|
||||
ArmSubsystem arm = new ArmSubsystem(hardwareMap);
|
||||
ClawSubsystem claw = new ClawSubsystem(hardwareMap);
|
||||
HangMotorSubsystem hang = new HangMotorSubsystem(hardwareMap);
|
||||
|
||||
|
||||
/*
|
||||
* Instantiate gamepad state holders
|
||||
*/
|
||||
Gamepad currentGamepad1 = new Gamepad();
|
||||
Gamepad previousGamepad1 = new Gamepad();
|
||||
|
||||
lift.init();
|
||||
wrist.initTeleOp();
|
||||
arm.initTeleOp();
|
||||
claw.init();
|
||||
waitForStart();
|
||||
runtime.reset();
|
||||
|
||||
|
||||
// run until the end of the match (driver presses STOP)
|
||||
while (opModeIsActive()) {
|
||||
|
||||
previousGamepad1.copy(currentGamepad1);
|
||||
currentGamepad1.copy(gamepad1);
|
||||
|
||||
if (currentGamepad1.dpad_up && !previousGamepad1.dpad_up) {
|
||||
arm.setPosition(arm.getPosition() + .05);
|
||||
}
|
||||
|
||||
if (currentGamepad1.dpad_down && !previousGamepad1.dpad_down) {
|
||||
arm.setPosition(arm.getPosition() - .05);
|
||||
}
|
||||
|
||||
if (currentGamepad1.b && !previousGamepad1.b) {
|
||||
claw.switchState();
|
||||
}
|
||||
|
||||
if (currentGamepad1.dpad_right && !previousGamepad1.dpad_right) {
|
||||
lift.toHighBucketPosition();
|
||||
}
|
||||
|
||||
if (currentGamepad1.dpad_left && !previousGamepad1.dpad_left) {
|
||||
lift.toLowBucketPosition();
|
||||
}
|
||||
|
||||
if (currentGamepad1.y && !previousGamepad1.y) {
|
||||
wrist.setPosition(wrist.getPosition() + .05);
|
||||
}
|
||||
|
||||
if (currentGamepad1.a && !previousGamepad1.a) {
|
||||
wrist.setPosition(wrist.getPosition() - .05);
|
||||
}
|
||||
|
||||
|
||||
if (currentGamepad1.right_bumper && !previousGamepad1.right_bumper) {
|
||||
lift.toHighBucketPosition();
|
||||
}
|
||||
|
||||
if (currentGamepad1.left_bumper && !previousGamepad1.left_bumper) {
|
||||
lift.toLowBucketPosition();
|
||||
|
||||
}
|
||||
if(currentGamepad1.left_trigger > 0){
|
||||
hang.setPower((double) currentGamepad1.left_trigger);
|
||||
}
|
||||
if(currentGamepad1.right_trigger > 0){
|
||||
hang.setPower((double) currentGamepad1.right_trigger);
|
||||
}
|
||||
|
||||
lift.update();
|
||||
|
||||
// Show the elapsed game time and wheel power.
|
||||
|
||||
telemetry.addData("Status", "Run Time: " + runtime.toString());
|
||||
telemetry.addData("Lift Drive Position", lift.getFixedPosition());
|
||||
telemetry.addData("Wrist Position", wrist.getPosition());
|
||||
telemetry.addData("Arm Position", arm.getPosition());
|
||||
telemetry.addData("Slide Ticks", lift.getCurrentPosition());
|
||||
telemetry.addData("Hook Ticks", hang.getCurrentPosition());
|
||||
telemetry.update();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,105 +0,0 @@
|
||||
package org.firstinspires.ftc.teamcode.subsystem;
|
||||
|
||||
import static org.firstinspires.ftc.teamcode.PedroConstants.BACK_LEFT_MOTOR;
|
||||
import static org.firstinspires.ftc.teamcode.PedroConstants.BACK_LEFT_MOTOR_DIRECTION;
|
||||
import static org.firstinspires.ftc.teamcode.PedroConstants.BACK_RIGHT_MOTOR;
|
||||
import static org.firstinspires.ftc.teamcode.PedroConstants.BACK_RIGHT_MOTOR_DIRECTION;
|
||||
import static org.firstinspires.ftc.teamcode.PedroConstants.FRONT_LEFT_MOTOR;
|
||||
import static org.firstinspires.ftc.teamcode.PedroConstants.FRONT_LEFT_MOTOR_DIRECTION;
|
||||
import static org.firstinspires.ftc.teamcode.PedroConstants.FRONT_RIGHT_MOTOR;
|
||||
import static org.firstinspires.ftc.teamcode.PedroConstants.FRONT_RIGHT_MOTOR_DIRECTION;
|
||||
import static org.firstinspires.ftc.teamcode.PedroConstants.MAX_POWER;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.acmerobotics.dashboard.telemetry.TelemetryPacket;
|
||||
import com.acmerobotics.roadrunner.Action;
|
||||
import com.qualcomm.robotcore.hardware.DcMotor;
|
||||
import com.qualcomm.robotcore.hardware.Gamepad;
|
||||
import com.qualcomm.robotcore.hardware.HardwareMap;
|
||||
|
||||
import org.firstinspires.ftc.robotcore.external.Telemetry;
|
||||
|
||||
public class MotorsSubsystem {
|
||||
|
||||
public HardwareMap hardwareMap;
|
||||
public Telemetry telemetry;
|
||||
|
||||
public DcMotor frontLeftMotor;
|
||||
public DcMotor backLeftMotor;
|
||||
public DcMotor frontRightMotor;
|
||||
public DcMotor backRightMotor;
|
||||
|
||||
public enum TravelState {
|
||||
STOPPED, MOVING
|
||||
}
|
||||
|
||||
public TravelState travelState;
|
||||
|
||||
public double power;
|
||||
|
||||
public MotorsSubsystem(HardwareMap hardwareMap, Telemetry telemetry) {
|
||||
this.hardwareMap = hardwareMap;
|
||||
this.telemetry = telemetry;
|
||||
this.power = MAX_POWER;
|
||||
}
|
||||
|
||||
public MotorsSubsystem(HardwareMap hardwareMap, Telemetry telemetry, double power) {
|
||||
this.hardwareMap = hardwareMap;
|
||||
this.telemetry = telemetry;
|
||||
this.power = power;
|
||||
}
|
||||
|
||||
public void init() {
|
||||
frontLeftMotor = hardwareMap.get(DcMotor.class, FRONT_LEFT_MOTOR);
|
||||
backLeftMotor = hardwareMap.get(DcMotor.class, BACK_LEFT_MOTOR);
|
||||
frontRightMotor = hardwareMap.get(DcMotor.class, FRONT_RIGHT_MOTOR);
|
||||
backRightMotor = hardwareMap.get(DcMotor.class, BACK_RIGHT_MOTOR);
|
||||
|
||||
frontLeftMotor.setDirection(FRONT_LEFT_MOTOR_DIRECTION);
|
||||
backLeftMotor.setDirection(BACK_LEFT_MOTOR_DIRECTION);
|
||||
frontRightMotor.setDirection(FRONT_RIGHT_MOTOR_DIRECTION);
|
||||
backRightMotor.setDirection(BACK_RIGHT_MOTOR_DIRECTION);
|
||||
|
||||
frontLeftMotor.setZeroPowerBehavior(DcMotor.ZeroPowerBehavior.BRAKE);
|
||||
backLeftMotor.setZeroPowerBehavior(DcMotor.ZeroPowerBehavior.BRAKE);
|
||||
frontRightMotor.setZeroPowerBehavior(DcMotor.ZeroPowerBehavior.BRAKE);
|
||||
backRightMotor.setZeroPowerBehavior(DcMotor.ZeroPowerBehavior.BRAKE);
|
||||
|
||||
this.setState(TravelState.STOPPED);
|
||||
}
|
||||
|
||||
public void setFrontLeftMotorPower(double power) {
|
||||
frontLeftMotor.setPower(power);
|
||||
}
|
||||
|
||||
public void setBackLeftMotorPower(double power) {
|
||||
backLeftMotor.setPower(power);
|
||||
}
|
||||
|
||||
public void setFrontRightMotorPower(double power) {
|
||||
frontRightMotor.setPower(power);
|
||||
}
|
||||
|
||||
public void setBackRightMotorPower(double power) {
|
||||
backRightMotor.setPower(power);
|
||||
}
|
||||
|
||||
|
||||
public void setState(TravelState travelState) {
|
||||
this.travelState = travelState;
|
||||
}
|
||||
|
||||
public TravelState getState() {
|
||||
return this.travelState;
|
||||
}
|
||||
|
||||
public void setPower(DcMotor motor, double power) {
|
||||
motor.setPower(power);
|
||||
if (power < 0.05) {
|
||||
this.setState(TravelState.MOVING);
|
||||
} else {
|
||||
this.setState(TravelState.STOPPED);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,117 +0,0 @@
|
||||
package org.firstinspires.ftc.teamcode.subsystem;
|
||||
|
||||
import static org.firstinspires.ftc.teamcode.PedroConstants.WRIST_SERVO;
|
||||
import static org.firstinspires.ftc.teamcode.configs.RobotConstants.wristBackwardBucket;
|
||||
import static org.firstinspires.ftc.teamcode.configs.RobotConstants.wristBucket;
|
||||
import static org.firstinspires.ftc.teamcode.configs.RobotConstants.wristFloor;
|
||||
import static org.firstinspires.ftc.teamcode.configs.RobotConstants.wristGrabBlueberrySkyhook;
|
||||
import static org.firstinspires.ftc.teamcode.configs.RobotConstants.wristHangBlueberrySkyhook;
|
||||
import static org.firstinspires.ftc.teamcode.configs.RobotConstants.wristInit;
|
||||
import static org.firstinspires.ftc.teamcode.configs.RobotConstants.wristPickup;
|
||||
import static org.firstinspires.ftc.teamcode.configs.RobotConstants.wristSpeciemen;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.acmerobotics.dashboard.telemetry.TelemetryPacket;
|
||||
import com.acmerobotics.roadrunner.Action;
|
||||
import com.acmerobotics.roadrunner.ftc.Actions;
|
||||
import com.qualcomm.robotcore.hardware.HardwareMap;
|
||||
import com.qualcomm.robotcore.hardware.ServoImplEx;
|
||||
|
||||
public class WristSubsystem {
|
||||
|
||||
public enum WristState {
|
||||
FLOOR, BUCKET, PICKUP, RUNG, SPECIMEN, GRAB_BLUEBERRY_SKYHOOK, HANG_BLUEBERRY_SKYHOOK, INIT, REVERSE_BUCKET
|
||||
}
|
||||
|
||||
public ServoImplEx wrist;
|
||||
public WristState state;
|
||||
|
||||
public WristSubsystem(HardwareMap hardwareMap) {
|
||||
this.wrist = hardwareMap.get(ServoImplEx.class, WRIST_SERVO);
|
||||
}
|
||||
|
||||
public class MoveToPosition implements Action {
|
||||
private double positionValue;
|
||||
private WristState positionState;
|
||||
|
||||
public MoveToPosition(double positionValue, WristState positionState) {
|
||||
this.positionValue = positionValue;
|
||||
this.positionState = positionState;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean run(@NonNull TelemetryPacket telemetryPacket) {
|
||||
setState(positionState);
|
||||
wrist.setPosition(positionValue);
|
||||
telemetryPacket.put("Wrist State", positionState);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public void grabBlueberrySkyhook(){
|
||||
setState(WristState.GRAB_BLUEBERRY_SKYHOOK);
|
||||
wrist.setPosition(wristGrabBlueberrySkyhook);
|
||||
}
|
||||
|
||||
|
||||
public void hangBlueberrySkyhook(){
|
||||
setState(WristState.HANG_BLUEBERRY_SKYHOOK);
|
||||
wrist.setPosition(wristHangBlueberrySkyhook);
|
||||
}
|
||||
public void toFloorPosition() {
|
||||
setState(WristState.FLOOR);
|
||||
wrist.setPosition(wristFloor);
|
||||
}
|
||||
|
||||
public void toBucketPosition() {
|
||||
setState(WristState.BUCKET);
|
||||
wrist.setPosition(wristBucket);
|
||||
}
|
||||
|
||||
public void toPickupPosition() {
|
||||
setState(WristState.PICKUP);
|
||||
wrist.setPosition(wristPickup);
|
||||
}
|
||||
public void toInitPosition(){
|
||||
setState(WristState.INIT);
|
||||
wrist.setPosition(wristInit);
|
||||
}
|
||||
public void InitAuto(){
|
||||
wrist.resetDeviceConfigurationForOpMode();
|
||||
toInitPosition();
|
||||
|
||||
}
|
||||
|
||||
public void setState(WristState wristState) {
|
||||
this.state = wristState;
|
||||
}
|
||||
|
||||
public void switchState() {
|
||||
if (state == WristState.FLOOR) {
|
||||
toPickupPosition();
|
||||
} else if (state == WristState.PICKUP) {
|
||||
toFloorPosition();
|
||||
}
|
||||
}
|
||||
public void toReverseBucket(){
|
||||
wrist.setPosition(wristBackwardBucket);
|
||||
setState(WristState.REVERSE_BUCKET);
|
||||
}
|
||||
public WristState getState() {
|
||||
return this.state;
|
||||
}
|
||||
|
||||
public void initTeleOp() {
|
||||
wrist.resetDeviceConfigurationForOpMode();
|
||||
toPickupPosition();
|
||||
}
|
||||
|
||||
public void setPosition(double position) {
|
||||
wrist.setPosition(position);
|
||||
}
|
||||
|
||||
public double getPosition() {
|
||||
return wrist.getPosition();
|
||||
}
|
||||
|
||||
}
|
@ -21,7 +21,7 @@ apply plugin: 'com.android.application'
|
||||
|
||||
android {
|
||||
|
||||
compileSdkVersion 30
|
||||
compileSdkVersion 29
|
||||
|
||||
signingConfigs {
|
||||
release {
|
||||
@ -113,6 +113,10 @@ android {
|
||||
packagingOptions {
|
||||
pickFirst '**/*.so'
|
||||
}
|
||||
sourceSets.main {
|
||||
jni.srcDirs = []
|
||||
jniLibs.srcDir rootProject.file('libs')
|
||||
}
|
||||
ndkVersion '21.3.6528147'
|
||||
}
|
||||
|
||||
|
@ -16,9 +16,6 @@ dependencies {
|
||||
implementation 'org.firstinspires.ftc:Vision:10.1.0'
|
||||
implementation 'androidx.appcompat:appcompat:1.2.0'
|
||||
|
||||
implementation "com.acmerobotics.roadrunner:ftc:0.1.14"
|
||||
implementation "com.acmerobotics.roadrunner:core:1.0.0"
|
||||
implementation "com.acmerobotics.roadrunner:actions:1.0.0"
|
||||
implementation "com.acmerobotics.dashboard:dashboard:0.4.16"
|
||||
implementation 'com.acmerobotics.dashboard:dashboard:0.4.5'
|
||||
}
|
||||
|
||||
|
@ -5,16 +5,13 @@
|
||||
*/
|
||||
|
||||
buildscript {
|
||||
ext {
|
||||
agp_version = '8.1.4'
|
||||
}
|
||||
repositories {
|
||||
mavenCentral()
|
||||
google()
|
||||
}
|
||||
dependencies {
|
||||
// Note for FTC Teams: Do not modify this yourself.
|
||||
classpath "com.android.tools.build:gradle:$agp_version"
|
||||
classpath 'com.android.tools.build:gradle:7.2.0'
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8,5 +8,3 @@ android.enableJetifier=false
|
||||
|
||||
# Allow Gradle to use up to 1 GB of RAM
|
||||
org.gradle.jvmargs=-Xmx1024M
|
||||
|
||||
android.nonTransitiveRClass=false
|
3
gradle/wrapper/gradle-wrapper.properties
vendored
3
gradle/wrapper/gradle-wrapper.properties
vendored
@ -1,6 +1,5 @@
|
||||
#Thu Dec 26 18:45:39 PST 2024
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
Reference in New Issue
Block a user