diff --git a/FtcRobotController/src/main/AndroidManifest.xml b/FtcRobotController/src/main/AndroidManifest.xml index 2161185c..787878b9 100644 --- a/FtcRobotController/src/main/AndroidManifest.xml +++ b/FtcRobotController/src/main/AndroidManifest.xml @@ -1,8 +1,8 @@ + android:versionCode="56" + android:versionName="10.1"> diff --git a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/BasicOmniOpMode_Linear.java b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/BasicOmniOpMode_Linear.java index 737a3a62..d4ef9afb 100644 --- a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/BasicOmniOpMode_Linear.java +++ b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/BasicOmniOpMode_Linear.java @@ -99,7 +99,7 @@ public void runOpMode() { rightFrontDrive.setDirection(DcMotor.Direction.FORWARD); rightBackDrive.setDirection(DcMotor.Direction.FORWARD); - // Wait for the game to start (driver presses PLAY) + // Wait for the game to start (driver presses START) telemetry.addData("Status", "Initialized"); telemetry.update(); diff --git a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/BasicOpMode_Iterative.java b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/BasicOpMode_Iterative.java index 85e21777..62b6db6b 100644 --- a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/BasicOpMode_Iterative.java +++ b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/BasicOpMode_Iterative.java @@ -83,14 +83,14 @@ public void init() { } /* - * Code to run REPEATEDLY after the driver hits INIT, but before they hit PLAY + * Code to run REPEATEDLY after the driver hits INIT, but before they hit START */ @Override public void init_loop() { } /* - * Code to run ONCE when the driver hits PLAY + * Code to run ONCE when the driver hits START */ @Override public void start() { @@ -98,7 +98,7 @@ public void start() { } /* - * Code to run REPEATEDLY after the driver hits PLAY but before they hit STOP + * Code to run REPEATEDLY after the driver hits START but before they hit STOP */ @Override public void loop() { diff --git a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/BasicOpMode_Linear.java b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/BasicOpMode_Linear.java index f2a62aba..82ef68ca 100644 --- a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/BasicOpMode_Linear.java +++ b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/BasicOpMode_Linear.java @@ -76,7 +76,7 @@ public void runOpMode() { leftDrive.setDirection(DcMotor.Direction.REVERSE); rightDrive.setDirection(DcMotor.Direction.FORWARD); - // Wait for the game to start (driver presses PLAY) + // Wait for the game to start (driver presses START) waitForStart(); runtime.reset(); diff --git a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptAprilTag.java b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptAprilTag.java index a2cb372e..8ec77dd8 100644 --- a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptAprilTag.java +++ b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptAprilTag.java @@ -29,6 +29,7 @@ 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; @@ -87,7 +88,7 @@ public void runOpMode() { // Wait for the DS start button to be touched. telemetry.addData("DS preview on/off", "3 dots, Camera Stream"); - telemetry.addData(">", "Touch Play to start OpMode"); + telemetry.addData(">", "Touch START to start OpMode"); telemetry.update(); waitForStart(); diff --git a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptAprilTagEasy.java b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptAprilTagEasy.java index d305d554..12dcf6e9 100644 --- a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptAprilTagEasy.java +++ b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptAprilTagEasy.java @@ -84,7 +84,7 @@ public void runOpMode() { // Wait for the DS start button to be touched. telemetry.addData("DS preview on/off", "3 dots, Camera Stream"); - telemetry.addData(">", "Touch Play to start OpMode"); + telemetry.addData(">", "Touch START to start OpMode"); telemetry.update(); waitForStart(); diff --git a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptAprilTagLocalization.java b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptAprilTagLocalization.java new file mode 100644 index 00000000..d90261ef --- /dev/null +++ b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptAprilTagLocalization.java @@ -0,0 +1,247 @@ +/* Copyright (c) 2024 Dryw Wade. 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.robotcontroller.external.samples; + +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.BuiltinCameraDirection; +import org.firstinspires.ftc.robotcore.external.hardware.camera.WebcamName; +import org.firstinspires.ftc.robotcore.external.navigation.AngleUnit; +import org.firstinspires.ftc.robotcore.external.navigation.DistanceUnit; +import org.firstinspires.ftc.robotcore.external.navigation.Position; +import org.firstinspires.ftc.robotcore.external.navigation.YawPitchRollAngles; +import org.firstinspires.ftc.vision.VisionPortal; +import org.firstinspires.ftc.vision.apriltag.AprilTagDetection; +import org.firstinspires.ftc.vision.apriltag.AprilTagProcessor; + +import java.util.List; + +/* + * This OpMode illustrates the basics of AprilTag based localization. + * + * For an introduction to AprilTags, see the FTC-DOCS link below: + * https://ftc-docs.firstinspires.org/en/latest/apriltag/vision_portal/apriltag_intro/apriltag-intro.html + * + * In this sample, any visible tag ID will be detected and displayed, but only tags that are included in the default + * "TagLibrary" will be used to compute the robot's location and orientation. This default TagLibrary contains + * the current Season's AprilTags and a small set of "test Tags" in the high number range. + * + * 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. + */ +@TeleOp(name = "Concept: AprilTag Localization", group = "Concept") +@Disabled +public class ConceptAprilTagLocalization extends LinearOpMode { + + private static final boolean USE_WEBCAM = true; // true for webcam, false for phone camera + + /** + * Variables to store the position and orientation of the camera on the robot. Setting these + * values requires a definition of the axes of the camera and robot: + * + * Camera axes: + * Origin location: Center of the lens + * Axes orientation: +x right, +y down, +z forward (from camera's perspective) + * + * Robot axes (this is typical, but you can define this however you want): + * Origin location: Center of the robot at field height + * Axes orientation: +x right, +y forward, +z upward + * + * Position: + * If all values are zero (no translation), that implies the camera is at the center of the + * robot. Suppose your camera is positioned 5 inches to the left, 7 inches forward, and 12 + * inches above the ground - you would need to set the position to (-5, 7, 12). + * + * Orientation: + * If all values are zero (no rotation), that implies the camera is pointing straight up. In + * most cases, you'll need to set the pitch to -90 degrees (rotation about the x-axis), meaning + * the camera is horizontal. Use a yaw of 0 if the camera is pointing forwards, +90 degrees if + * it's pointing straight left, -90 degrees for straight right, etc. You can also set the roll + * to +/-90 degrees if it's vertical, or 180 degrees if it's upside-down. + */ + private Position cameraPosition = new Position(DistanceUnit.INCH, + 0, 0, 0, 0); + private YawPitchRollAngles cameraOrientation = new YawPitchRollAngles(AngleUnit.DEGREES, + 0, -90, 0, 0); + + /** + * The variable to store our instance of the AprilTag processor. + */ + private AprilTagProcessor aprilTag; + + /** + * The variable to store our instance of the vision portal. + */ + private VisionPortal visionPortal; + + @Override + public void runOpMode() { + + initAprilTag(); + + // Wait for the DS start button to be touched. + telemetry.addData("DS preview on/off", "3 dots, Camera Stream"); + telemetry.addData(">", "Touch START to start OpMode"); + telemetry.update(); + waitForStart(); + + while (opModeIsActive()) { + + telemetryAprilTag(); + + // Push telemetry to the Driver Station. + telemetry.update(); + + // Save CPU resources; can resume streaming when needed. + if (gamepad1.dpad_down) { + visionPortal.stopStreaming(); + } else if (gamepad1.dpad_up) { + visionPortal.resumeStreaming(); + } + + // Share the CPU. + sleep(20); + } + + // Save more CPU resources when camera is no longer needed. + visionPortal.close(); + + } // end method runOpMode() + + /** + * Initialize the AprilTag processor. + */ + private void initAprilTag() { + + // Create the AprilTag processor. + aprilTag = new AprilTagProcessor.Builder() + + // The following default settings are available to un-comment and edit as needed. + //.setDrawAxes(false) + //.setDrawCubeProjection(false) + //.setDrawTagOutline(true) + //.setTagFamily(AprilTagProcessor.TagFamily.TAG_36h11) + //.setTagLibrary(AprilTagGameDatabase.getCenterStageTagLibrary()) + //.setOutputUnits(DistanceUnit.INCH, AngleUnit.DEGREES) + .setCameraPose(cameraPosition, cameraOrientation) + + // == CAMERA CALIBRATION == + // If you do not manually specify calibration parameters, the SDK will attempt + // to load a predefined calibration for your camera. + //.setLensIntrinsics(578.272, 578.272, 402.145, 221.506) + // ... these parameters are fx, fy, cx, cy. + + .build(); + + // Adjust Image Decimation to trade-off detection-range for detection-rate. + // eg: Some typical detection data using a Logitech C920 WebCam + // Decimation = 1 .. Detect 2" Tag from 10 feet away at 10 Frames per second + // Decimation = 2 .. Detect 2" Tag from 6 feet away at 22 Frames per second + // Decimation = 3 .. Detect 2" Tag from 4 feet away at 30 Frames Per Second (default) + // Decimation = 3 .. Detect 5" Tag from 10 feet away at 30 Frames Per Second (default) + // Note: Decimation can be changed on-the-fly to adapt during a match. + //aprilTag.setDecimation(3); + + // Create the vision portal by using a builder. + VisionPortal.Builder builder = new VisionPortal.Builder(); + + // Set the camera (webcam vs. built-in RC phone camera). + if (USE_WEBCAM) { + builder.setCamera(hardwareMap.get(WebcamName.class, "Webcam 1")); + } else { + builder.setCamera(BuiltinCameraDirection.BACK); + } + + // Choose a camera resolution. Not all cameras support all resolutions. + //builder.setCameraResolution(new Size(640, 480)); + + // Enable the RC preview (LiveView). Set "false" to omit camera monitoring. + //builder.enableLiveView(true); + + // Set the stream format; MJPEG uses less bandwidth than default YUY2. + //builder.setStreamFormat(VisionPortal.StreamFormat.YUY2); + + // Choose whether or not LiveView stops if no processors are enabled. + // If set "true", monitor shows solid orange screen if no processors enabled. + // If set "false", monitor shows camera view without annotations. + //builder.setAutoStopLiveView(false); + + // Set and enable the processor. + builder.addProcessor(aprilTag); + + // Build the Vision Portal, using the above settings. + visionPortal = builder.build(); + + // Disable or re-enable the aprilTag processor at any time. + //visionPortal.setProcessorEnabled(aprilTag, true); + + } // end method initAprilTag() + + /** + * Add telemetry about AprilTag detections. + */ + private void telemetryAprilTag() { + + List currentDetections = aprilTag.getDetections(); + telemetry.addData("# AprilTags Detected", currentDetections.size()); + + // Step through the list of detections and display info for each one. + for (AprilTagDetection detection : currentDetections) { + if (detection.metadata != null) { + telemetry.addLine(String.format("\n==== (ID %d) %s", detection.id, detection.metadata.name)); + telemetry.addLine(String.format("XYZ %6.1f %6.1f %6.1f (inch)", + detection.robotPose.getPosition().x, + detection.robotPose.getPosition().y, + detection.robotPose.getPosition().z)); + telemetry.addLine(String.format("PRY %6.1f %6.1f %6.1f (deg)", + detection.robotPose.getOrientation().getPitch(AngleUnit.DEGREES), + detection.robotPose.getOrientation().getRoll(AngleUnit.DEGREES), + detection.robotPose.getOrientation().getYaw(AngleUnit.DEGREES))); + } else { + telemetry.addLine(String.format("\n==== (ID %d) Unknown", detection.id)); + telemetry.addLine(String.format("Center %6.0f %6.0f (pixels)", detection.center.x, detection.center.y)); + } + } // end for() loop + + // Add "key" information to telemetry + telemetry.addLine("\nkey:\nXYZ = X (Right), Y (Forward), Z (Up) dist."); + telemetry.addLine("PRY = Pitch, Roll & Yaw (XYZ Rotation)"); + + } // end method telemetryAprilTag() + +} // end class diff --git a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptAprilTagMultiPortal.java b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptAprilTagMultiPortal.java new file mode 100644 index 00000000..da5cc3ed --- /dev/null +++ b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptAprilTagMultiPortal.java @@ -0,0 +1,104 @@ +/* Copyright (c) 2024 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.robotcontroller.external.samples; + +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.BuiltinCameraDirection; +import org.firstinspires.ftc.robotcore.external.hardware.camera.WebcamName; +import org.firstinspires.ftc.vision.VisionPortal; +import org.firstinspires.ftc.vision.apriltag.AprilTagProcessor; + +/** + * This OpMode demonstrates the basics of using multiple vision portals simultaneously + */ +@TeleOp(name = "Concept: AprilTagMultiPortal", group = "Concept") +@Disabled +public class ConceptAprilTagMultiPortal extends LinearOpMode +{ + VisionPortal portal1; + VisionPortal portal2; + + AprilTagProcessor aprilTagProcessor1; + AprilTagProcessor aprilTagProcessor2; + + @Override + public void runOpMode() throws InterruptedException + { + // Because we want to show two camera feeds simultaneously, we need to inform + // the SDK that we want it to split the camera monitor area into two smaller + // areas for us. It will then give us View IDs which we can pass to the individual + // vision portals to allow them to properly hook into the UI in tandem. + int[] viewIds = VisionPortal.makeMultiPortalView(2, VisionPortal.MultiPortalLayout.VERTICAL); + + // We extract the two view IDs from the array to make our lives a little easier later. + // NB: the array is 2 long because we asked for 2 portals up above. + int portal1ViewId = viewIds[0]; + int portal2ViewId = viewIds[1]; + + // If we want to run AprilTag detection on two portals simultaneously, + // we need to create two distinct instances of the AprilTag processor, + // one for each portal. If you want to see more detail about different + // options that you have when creating these processors, go check out + // the ConceptAprilTag OpMode. + aprilTagProcessor1 = AprilTagProcessor.easyCreateWithDefaults(); + aprilTagProcessor2 = AprilTagProcessor.easyCreateWithDefaults(); + + // Now we build both portals. The CRITICAL thing to notice here is the call to + // setLiveViewContainerId(), where we pass in the IDs we received earlier from + // makeMultiPortalView(). + portal1 = new VisionPortal.Builder() + .setCamera(hardwareMap.get(WebcamName.class, "Webcam 1")) + .setLiveViewContainerId(portal1ViewId) + .addProcessor(aprilTagProcessor1) + .build(); + portal2 = new VisionPortal.Builder() + .setCamera(hardwareMap.get(WebcamName.class, "Webcam 2")) + .setLiveViewContainerId(portal2ViewId) + .addProcessor(aprilTagProcessor2) + .build(); + + waitForStart(); + + // Main Loop + while (opModeIsActive()) + { + // Just show some basic telemetry to demonstrate both processors are working in parallel + // on their respective cameras. If you want to see more detail about the information you + // can get back from the processor, you should look at ConceptAprilTag. + telemetry.addData("Number of tags in Camera 1", aprilTagProcessor1.getDetections().size()); + telemetry.addData("Number of tags in Camera 2", aprilTagProcessor2.getDetections().size()); + telemetry.update(); + sleep(20); + } + } +} diff --git a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptAprilTagOptimizeExposure.java b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptAprilTagOptimizeExposure.java index 362ad98f..a3d23467 100644 --- a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptAprilTagOptimizeExposure.java +++ b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptAprilTagOptimizeExposure.java @@ -98,7 +98,7 @@ public class ConceptAprilTagOptimizeExposure extends LinearOpMode // Wait for the match to begin. telemetry.addData("Camera preview on/off", "3 dots, Camera Stream"); - telemetry.addData(">", "Touch Play to start OpMode"); + telemetry.addData(">", "Touch START to start OpMode"); telemetry.update(); waitForStart(); diff --git a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptAprilTagSwitchableCameras.java b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptAprilTagSwitchableCameras.java index 92852243..7ee1064b 100644 --- a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptAprilTagSwitchableCameras.java +++ b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptAprilTagSwitchableCameras.java @@ -77,7 +77,7 @@ public void runOpMode() { // Wait for the DS start button to be touched. telemetry.addData("DS preview on/off", "3 dots, Camera Stream"); - telemetry.addData(">", "Touch Play to start OpMode"); + telemetry.addData(">", "Touch START to start OpMode"); telemetry.update(); waitForStart(); diff --git a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptDoubleVision.java b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptDoubleVision.java deleted file mode 100644 index 1d50049c..00000000 --- a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptDoubleVision.java +++ /dev/null @@ -1,202 +0,0 @@ -/* Copyright (c) 2023 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.robotcontroller.external.samples; - -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.BuiltinCameraDirection; -import org.firstinspires.ftc.robotcore.external.hardware.camera.WebcamName; -import org.firstinspires.ftc.robotcore.external.tfod.Recognition; -import org.firstinspires.ftc.vision.VisionPortal; -import org.firstinspires.ftc.vision.apriltag.AprilTagDetection; -import org.firstinspires.ftc.vision.apriltag.AprilTagProcessor; -import org.firstinspires.ftc.vision.tfod.TfodProcessor; - -import java.util.List; - -/* - * This OpMode illustrates the basics of using both AprilTag recognition and TensorFlow - * Object Detection. - * - * 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. - */ -@TeleOp(name = "Concept: Double Vision", group = "Concept") -@Disabled -public class ConceptDoubleVision extends LinearOpMode { - private static final boolean USE_WEBCAM = true; // true for webcam, false for phone camera - - /** - * The variable to store our instance of the AprilTag processor. - */ - private AprilTagProcessor aprilTag; - - /** - * The variable to store our instance of the TensorFlow Object Detection processor. - */ - private TfodProcessor tfod; - - /** - * The variable to store our instance of the vision portal. - */ - private VisionPortal myVisionPortal; - - @Override - public void runOpMode() { - initDoubleVision(); - - // This OpMode loops continuously, allowing the user to switch between - // AprilTag and TensorFlow Object Detection (TFOD) image processors. - while (!isStopRequested()) { - - if (opModeInInit()) { - telemetry.addData("DS preview on/off","3 dots, Camera Stream"); - telemetry.addLine(); - telemetry.addLine("----------------------------------------"); - } - - if (myVisionPortal.getProcessorEnabled(aprilTag)) { - // User instructions: Dpad left or Dpad right. - telemetry.addLine("Dpad Left to disable AprilTag"); - telemetry.addLine(); - telemetryAprilTag(); - } else { - telemetry.addLine("Dpad Right to enable AprilTag"); - } - telemetry.addLine(); - telemetry.addLine("----------------------------------------"); - if (myVisionPortal.getProcessorEnabled(tfod)) { - telemetry.addLine("Dpad Down to disable TFOD"); - telemetry.addLine(); - telemetryTfod(); - } else { - telemetry.addLine("Dpad Up to enable TFOD"); - } - - // Push telemetry to the Driver Station. - telemetry.update(); - - if (gamepad1.dpad_left) { - myVisionPortal.setProcessorEnabled(aprilTag, false); - } else if (gamepad1.dpad_right) { - myVisionPortal.setProcessorEnabled(aprilTag, true); - } - if (gamepad1.dpad_down) { - myVisionPortal.setProcessorEnabled(tfod, false); - } else if (gamepad1.dpad_up) { - myVisionPortal.setProcessorEnabled(tfod, true); - } - - sleep(20); - - } // end while loop - - } // end method runOpMode() - - - /** - * Initialize AprilTag and TFOD. - */ - private void initDoubleVision() { - // ----------------------------------------------------------------------------------------- - // AprilTag Configuration - // ----------------------------------------------------------------------------------------- - - aprilTag = new AprilTagProcessor.Builder() - .build(); - - // ----------------------------------------------------------------------------------------- - // TFOD Configuration - // ----------------------------------------------------------------------------------------- - - tfod = new TfodProcessor.Builder() - .build(); - - // ----------------------------------------------------------------------------------------- - // Camera Configuration - // ----------------------------------------------------------------------------------------- - - if (USE_WEBCAM) { - myVisionPortal = new VisionPortal.Builder() - .setCamera(hardwareMap.get(WebcamName.class, "Webcam 1")) - .addProcessors(tfod, aprilTag) - .build(); - } else { - myVisionPortal = new VisionPortal.Builder() - .setCamera(BuiltinCameraDirection.BACK) - .addProcessors(tfod, aprilTag) - .build(); - } - } // end initDoubleVision() - - /** - * Add telemetry about AprilTag detections. - */ - private void telemetryAprilTag() { - List currentDetections = aprilTag.getDetections(); - telemetry.addData("# AprilTags Detected", currentDetections.size()); - - // Step through the list of detections and display info for each one. - for (AprilTagDetection detection : currentDetections) { - if (detection.metadata != null) { - telemetry.addLine(String.format("\n==== (ID %d) %s", detection.id, detection.metadata.name)); - telemetry.addLine(String.format("XYZ %6.1f %6.1f %6.1f (inch)", detection.ftcPose.x, detection.ftcPose.y, detection.ftcPose.z)); - telemetry.addLine(String.format("PRY %6.1f %6.1f %6.1f (deg)", detection.ftcPose.pitch, detection.ftcPose.roll, detection.ftcPose.yaw)); - telemetry.addLine(String.format("RBE %6.1f %6.1f %6.1f (inch, deg, deg)", detection.ftcPose.range, detection.ftcPose.bearing, detection.ftcPose.elevation)); - } else { - telemetry.addLine(String.format("\n==== (ID %d) Unknown", detection.id)); - telemetry.addLine(String.format("Center %6.0f %6.0f (pixels)", detection.center.x, detection.center.y)); - } - } // end for() loop - - } // end method telemetryAprilTag() - - /** - * Add telemetry about TensorFlow Object Detection (TFOD) recognitions. - */ - private void telemetryTfod() { - List currentRecognitions = tfod.getRecognitions(); - telemetry.addData("# Objects Detected", currentRecognitions.size()); - - // Step through the list of recognitions and display info for each one. - for (Recognition recognition : currentRecognitions) { - double x = (recognition.getLeft() + recognition.getRight()) / 2 ; - double y = (recognition.getTop() + recognition.getBottom()) / 2 ; - - telemetry.addData(""," "); - telemetry.addData("Image", "%s (%.0f %% Conf.)", recognition.getLabel(), recognition.getConfidence() * 100); - telemetry.addData("- Position", "%.0f / %.0f", x, y); - telemetry.addData("- Size", "%.0f x %.0f", recognition.getWidth(), recognition.getHeight()); - } // end for() loop - - } // end method telemetryTfod() - -} // end class diff --git a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptExternalHardwareClass.java b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptExternalHardwareClass.java index c558569b..8dc6537b 100644 --- a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptExternalHardwareClass.java +++ b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptExternalHardwareClass.java @@ -83,7 +83,7 @@ public void runOpMode() { robot.init(); // Send telemetry message to signify robot waiting; - // Wait for the game to start (driver presses PLAY) + // Wait for the game to start (driver presses START) waitForStart(); // run until the end of the match (driver presses STOP) diff --git a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptLEDStick.java b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptLEDStick.java new file mode 100644 index 00000000..01729bbb --- /dev/null +++ b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptLEDStick.java @@ -0,0 +1,123 @@ +package org.firstinspires.ftc.robotcontroller.external.samples; +/* + Copyright (c) 2021-24 Alan Smith + + 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 Alan Smith 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 FITNESSFOR 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 android.graphics.Color; + +import com.qualcomm.hardware.sparkfun.SparkFunLEDStick; +import com.qualcomm.robotcore.eventloop.opmode.Disabled; +import com.qualcomm.robotcore.eventloop.opmode.OpMode; +import com.qualcomm.robotcore.eventloop.opmode.TeleOp; +import com.qualcomm.robotcore.util.Range; + +/* + * This OpMode illustrates how to use the SparkFun QWIIC LED Strip + * + * This is a simple way to add a strip of 10 LEDs to your robot where you can set the color of each + * LED or the whole strip. This allows for driver feedback or even just fun ways to show your team + * colors. + * + * Why? + * Because more LEDs == more fun!! + * + * This OpMode assumes that the QWIIC LED Stick is attached to an I2C interface named "back_leds" in the robot configuration. + * + * 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 + * + * You can buy this product here: https://www.sparkfun.com/products/18354 + * Don't forget to also buy this to make it easy to connect to your Control or Expansion Hub: + * https://www.sparkfun.com/products/25596 + */ +@TeleOp(name = "Concept: LED Stick", group = "Concept") +@Disabled +public class ConceptLEDStick extends OpMode { + private boolean wasUp; + private boolean wasDown; + private int brightness = 5; // this needs to be between 0 and 31 + private final static double END_GAME_TIME = 120 - 30; + + private SparkFunLEDStick ledStick; + + @Override + public void init() { + ledStick = hardwareMap.get(SparkFunLEDStick.class, "back_leds"); + ledStick.setBrightness(brightness); + ledStick.setColor(Color.GREEN); + } + + @Override + public void start() { + resetRuntime(); + } + + @Override + public void loop() { + telemetry.addLine("Hold the A button to turn blue"); + telemetry.addLine("Hold the B button to turn red"); + telemetry.addLine("Hold the left bumper to turn off"); + telemetry.addLine("Use DPAD Up/Down to change brightness"); + + if (getRuntime() > END_GAME_TIME) { + int[] ledColors = {Color.RED, Color.YELLOW, Color.RED, Color.YELLOW, Color.RED, + Color.YELLOW, Color.RED, Color.YELLOW, Color.RED, Color.YELLOW}; + ledStick.setColors(ledColors); + } else if (gamepad1.a) { + ledStick.setColor(Color.BLUE); + } else if (gamepad1.b) { + ledStick.setColor(Color.RED); + } else if (gamepad1.left_bumper) { + ledStick.turnAllOff(); + } else { + ledStick.setColor(Color.GREEN); + } + + /* + * Use DPAD up and down to change brightness + */ + int newBrightness = brightness; + if (gamepad1.dpad_up && !wasUp) { + newBrightness = brightness + 1; + } else if (gamepad1.dpad_down && !wasDown) { + newBrightness = brightness - 1; + } + if (newBrightness != brightness) { + brightness = Range.clip(newBrightness, 0, 31); + ledStick.setBrightness(brightness); + } + telemetry.addData("Brightness", brightness); + + wasDown = gamepad1.dpad_down; + wasUp = gamepad1.dpad_up; + } +} diff --git a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptMotorBulkRead.java b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptMotorBulkRead.java index 3bade8b6..5439f780 100644 --- a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptMotorBulkRead.java +++ b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptMotorBulkRead.java @@ -110,7 +110,7 @@ public void runOpMode() { ElapsedTime timer = new ElapsedTime(); - telemetry.addData(">", "Press play to start tests"); + telemetry.addData(">", "Press START to start tests"); telemetry.addData(">", "Test results will update for each access method."); telemetry.update(); waitForStart(); diff --git a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptNullOp.java b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptNullOp.java index d37c7585..846ae224 100644 --- a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptNullOp.java +++ b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptNullOp.java @@ -53,7 +53,7 @@ public void init() { /** * This method will be called repeatedly during the period between when - * the init button is pressed and when the play button is pressed (or the + * the INIT button is pressed and when the START button is pressed (or the * OpMode is stopped). */ @Override @@ -61,7 +61,7 @@ public void init_loop() { } /** - * This method will be called once, when the play button is pressed. + * This method will be called once, when the START button is pressed. */ @Override public void start() { @@ -70,7 +70,7 @@ public void start() { /** * This method will be called repeatedly during the period between when - * the play button is pressed and when the OpMode is stopped. + * the START button is pressed and when the OpMode is stopped. */ @Override public void loop() { diff --git a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptRevLED.java b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptRevLED.java new file mode 100644 index 00000000..9c168d50 --- /dev/null +++ b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptRevLED.java @@ -0,0 +1,78 @@ +/* + Copyright (c) 2024 Alan Smith + 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 Alan Smith 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 FITNESSFOR 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.robotcontroller.external.samples; + +/* + * This OpMode illustrates how to use the REV Digital Indicator + * + * This is a simple way to add the REV Digital Indicator which has a red and green LED. + * (and as you may remember, red + green = yellow so when they are both on you can get yellow) + * + * Why? + * You can use this to show information to the driver. For example, green might be that you can + * pick up more game elements and red would be that you already have the possession limit. + * + * This OpMode assumes that the REV Digital Indicator is setup as 2 Digital Channels named + * front_led_green and front_led_red. (the green should be the lower of the 2 channels it is plugged + * into and the red should be the higher) + * + * 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 + * + * You can buy this product here: https://www.revrobotics.com/rev-31-2010/ + */ +import com.qualcomm.robotcore.eventloop.opmode.Disabled; +import com.qualcomm.robotcore.eventloop.opmode.OpMode; +import com.qualcomm.robotcore.eventloop.opmode.TeleOp; +import com.qualcomm.robotcore.hardware.LED; + +@TeleOp(name = "Concept: RevLED", group = "Concept") +@Disabled +public class ConceptRevLED extends OpMode { + LED frontLED_red; + LED frontLED_green; + + @Override + public void init() { + frontLED_green = hardwareMap.get(LED.class, "front_led_green"); + frontLED_red = hardwareMap.get(LED.class, "front_led_red"); + } + + @Override + public void loop() { + if (gamepad1.a) { + frontLED_red.on(); + } else { + frontLED_red.off(); + } + if (gamepad1.b) { + frontLED_green.on(); + } else { + frontLED_green.off(); + } + } +} diff --git a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptRevSPARKMini.java b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptRevSPARKMini.java index 97eaa3a1..e2f46773 100644 --- a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptRevSPARKMini.java +++ b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptRevSPARKMini.java @@ -38,8 +38,9 @@ /* - * This OpMode executes a basic Tank Drive Teleop for a two wheeled robot using two REV SPARKminis. - * To use this example, connect two REV SPARKminis into servo ports on the Expansion Hub. On the + * This OpMode demonstrates a POV Drive system, with commented-out code for a Tank Drive system, + * for a two wheeled robot using two REV SPARKminis. + * To use this example, connect two REV SPARKminis into servo ports on the Control Hub. On the * robot configuration, use the drop down list under 'Servos' to select 'REV SPARKmini Controller' * and name them 'left_drive' and 'right_drive'. * @@ -62,8 +63,7 @@ public void runOpMode() { telemetry.update(); // Initialize the hardware variables. Note that the strings used here as parameters - // to 'get' must correspond to the names assigned during the robot configuration - // step (using the FTC Robot Controller app on the phone). + // to 'get' must correspond to the names assigned during robot configuration. leftDrive = hardwareMap.get(DcMotorSimple.class, "left_drive"); rightDrive = hardwareMap.get(DcMotorSimple.class, "right_drive"); @@ -72,7 +72,7 @@ public void runOpMode() { leftDrive.setDirection(DcMotorSimple.Direction.FORWARD); rightDrive.setDirection(DcMotorSimple.Direction.REVERSE); - // Wait for the game to start (driver presses PLAY) + // Wait for the game to start (driver presses START) waitForStart(); runtime.reset(); diff --git a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptSoundsASJava.java b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptSoundsASJava.java index f0a855fa..1ceaa17d 100644 --- a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptSoundsASJava.java +++ b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptSoundsASJava.java @@ -100,7 +100,7 @@ public void runOpMode() { telemetry.addData("gold resource", goldFound ? "Found" : "NOT found\n Add gold.wav to /src/main/res/raw" ); telemetry.addData("silver resource", silverFound ? "Found" : "Not found\n Add silver.wav to /src/main/res/raw" ); - // Wait for the game to start (driver presses PLAY) + // Wait for the game to start (driver presses START) telemetry.addData(">", "Press Start to continue"); telemetry.update(); waitForStart(); diff --git a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptTensorFlowObjectDetection.java b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptTensorFlowObjectDetection.java deleted file mode 100644 index 014444ee..00000000 --- a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptTensorFlowObjectDetection.java +++ /dev/null @@ -1,198 +0,0 @@ -/* Copyright (c) 2019 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.robotcontroller.external.samples; - -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.BuiltinCameraDirection; -import org.firstinspires.ftc.robotcore.external.hardware.camera.WebcamName; -import org.firstinspires.ftc.robotcore.external.tfod.Recognition; -import org.firstinspires.ftc.vision.VisionPortal; -import org.firstinspires.ftc.vision.tfod.TfodProcessor; - -import java.util.List; - -/* - * This OpMode illustrates the basics of TensorFlow Object Detection, - * including Java Builder structures for specifying Vision 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. - */ -@TeleOp(name = "Concept: TensorFlow Object Detection", group = "Concept") -@Disabled -public class ConceptTensorFlowObjectDetection extends LinearOpMode { - - private static final boolean USE_WEBCAM = true; // true for webcam, false for phone camera - - // TFOD_MODEL_ASSET points to a model file stored in the project Asset location, - // this is only used for Android Studio when using models in Assets. - private static final String TFOD_MODEL_ASSET = "MyModelStoredAsAsset.tflite"; - // TFOD_MODEL_FILE points to a model file stored onboard the Robot Controller's storage, - // this is used when uploading models directly to the RC using the model upload interface. - private static final String TFOD_MODEL_FILE = "/sdcard/FIRST/tflitemodels/myCustomModel.tflite"; - // Define the labels recognized in the model for TFOD (must be in training order!) - private static final String[] LABELS = { - "Pixel", - }; - - /** - * The variable to store our instance of the TensorFlow Object Detection processor. - */ - private TfodProcessor tfod; - - /** - * The variable to store our instance of the vision portal. - */ - private VisionPortal visionPortal; - - @Override - public void runOpMode() { - - initTfod(); - - // Wait for the DS start button to be touched. - telemetry.addData("DS preview on/off", "3 dots, Camera Stream"); - telemetry.addData(">", "Touch Play to start OpMode"); - telemetry.update(); - waitForStart(); - - if (opModeIsActive()) { - while (opModeIsActive()) { - - telemetryTfod(); - - // Push telemetry to the Driver Station. - telemetry.update(); - - // Save CPU resources; can resume streaming when needed. - if (gamepad1.dpad_down) { - visionPortal.stopStreaming(); - } else if (gamepad1.dpad_up) { - visionPortal.resumeStreaming(); - } - - // Share the CPU. - sleep(20); - } - } - - // Save more CPU resources when camera is no longer needed. - visionPortal.close(); - - } // end runOpMode() - - /** - * Initialize the TensorFlow Object Detection processor. - */ - private void initTfod() { - - // Create the TensorFlow processor by using a builder. - tfod = new TfodProcessor.Builder() - - // With the following lines commented out, the default TfodProcessor Builder - // will load the default model for the season. To define a custom model to load, - // choose one of the following: - // Use setModelAssetName() if the custom TF Model is built in as an asset (AS only). - // Use setModelFileName() if you have downloaded a custom team model to the Robot Controller. - //.setModelAssetName(TFOD_MODEL_ASSET) - //.setModelFileName(TFOD_MODEL_FILE) - - // The following default settings are available to un-comment and edit as needed to - // set parameters for custom models. - //.setModelLabels(LABELS) - //.setIsModelTensorFlow2(true) - //.setIsModelQuantized(true) - //.setModelInputSize(300) - //.setModelAspectRatio(16.0 / 9.0) - - .build(); - - // Create the vision portal by using a builder. - VisionPortal.Builder builder = new VisionPortal.Builder(); - - // Set the camera (webcam vs. built-in RC phone camera). - if (USE_WEBCAM) { - builder.setCamera(hardwareMap.get(WebcamName.class, "Webcam 1")); - } else { - builder.setCamera(BuiltinCameraDirection.BACK); - } - - // Choose a camera resolution. Not all cameras support all resolutions. - //builder.setCameraResolution(new Size(640, 480)); - - // Enable the RC preview (LiveView). Set "false" to omit camera monitoring. - //builder.enableLiveView(true); - - // Set the stream format; MJPEG uses less bandwidth than default YUY2. - //builder.setStreamFormat(VisionPortal.StreamFormat.YUY2); - - // Choose whether or not LiveView stops if no processors are enabled. - // If set "true", monitor shows solid orange screen if no processors enabled. - // If set "false", monitor shows camera view without annotations. - //builder.setAutoStopLiveView(false); - - // Set and enable the processor. - builder.addProcessor(tfod); - - // Build the Vision Portal, using the above settings. - visionPortal = builder.build(); - - // Set confidence threshold for TFOD recognitions, at any time. - //tfod.setMinResultConfidence(0.75f); - - // Disable or re-enable the TFOD processor at any time. - //visionPortal.setProcessorEnabled(tfod, true); - - } // end method initTfod() - - /** - * Add telemetry about TensorFlow Object Detection (TFOD) recognitions. - */ - private void telemetryTfod() { - - List currentRecognitions = tfod.getRecognitions(); - telemetry.addData("# Objects Detected", currentRecognitions.size()); - - // Step through the list of recognitions and display info for each one. - for (Recognition recognition : currentRecognitions) { - double x = (recognition.getLeft() + recognition.getRight()) / 2 ; - double y = (recognition.getTop() + recognition.getBottom()) / 2 ; - - telemetry.addData(""," "); - telemetry.addData("Image", "%s (%.0f %% Conf.)", recognition.getLabel(), recognition.getConfidence() * 100); - telemetry.addData("- Position", "%.0f / %.0f", x, y); - telemetry.addData("- Size", "%.0f x %.0f", recognition.getWidth(), recognition.getHeight()); - } // end for() loop - - } // end method telemetryTfod() - -} // end class diff --git a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptTensorFlowObjectDetectionEasy.java b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptTensorFlowObjectDetectionEasy.java deleted file mode 100644 index 5c1b7120..00000000 --- a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptTensorFlowObjectDetectionEasy.java +++ /dev/null @@ -1,142 +0,0 @@ -/* Copyright (c) 2019 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.robotcontroller.external.samples; - -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.BuiltinCameraDirection; -import org.firstinspires.ftc.robotcore.external.hardware.camera.WebcamName; -import org.firstinspires.ftc.robotcore.external.tfod.Recognition; -import org.firstinspires.ftc.vision.VisionPortal; -import org.firstinspires.ftc.vision.tfod.TfodProcessor; - -import java.util.List; - -/* - * This OpMode illustrates the basics of TensorFlow Object Detection, using - * the easiest way. - * - * 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. - */ -@TeleOp(name = "Concept: TensorFlow Object Detection Easy", group = "Concept") -@Disabled -public class ConceptTensorFlowObjectDetectionEasy extends LinearOpMode { - - private static final boolean USE_WEBCAM = true; // true for webcam, false for phone camera - - /** - * The variable to store our instance of the TensorFlow Object Detection processor. - */ - private TfodProcessor tfod; - - /** - * The variable to store our instance of the vision portal. - */ - private VisionPortal visionPortal; - - @Override - public void runOpMode() { - - initTfod(); - - // Wait for the DS start button to be touched. - telemetry.addData("DS preview on/off", "3 dots, Camera Stream"); - telemetry.addData(">", "Touch Play to start OpMode"); - telemetry.update(); - waitForStart(); - - if (opModeIsActive()) { - while (opModeIsActive()) { - - telemetryTfod(); - - // Push telemetry to the Driver Station. - telemetry.update(); - - // Save CPU resources; can resume streaming when needed. - if (gamepad1.dpad_down) { - visionPortal.stopStreaming(); - } else if (gamepad1.dpad_up) { - visionPortal.resumeStreaming(); - } - - // Share the CPU. - sleep(20); - } - } - - // Save more CPU resources when camera is no longer needed. - visionPortal.close(); - - } // end runOpMode() - - /** - * Initialize the TensorFlow Object Detection processor. - */ - private void initTfod() { - - // Create the TensorFlow processor the easy way. - tfod = TfodProcessor.easyCreateWithDefaults(); - - // Create the vision portal the easy way. - if (USE_WEBCAM) { - visionPortal = VisionPortal.easyCreateWithDefaults( - hardwareMap.get(WebcamName.class, "Webcam 1"), tfod); - } else { - visionPortal = VisionPortal.easyCreateWithDefaults( - BuiltinCameraDirection.BACK, tfod); - } - - } // end method initTfod() - - /** - * Add telemetry about TensorFlow Object Detection (TFOD) recognitions. - */ - private void telemetryTfod() { - - List currentRecognitions = tfod.getRecognitions(); - telemetry.addData("# Objects Detected", currentRecognitions.size()); - - // Step through the list of recognitions and display info for each one. - for (Recognition recognition : currentRecognitions) { - double x = (recognition.getLeft() + recognition.getRight()) / 2 ; - double y = (recognition.getTop() + recognition.getBottom()) / 2 ; - - telemetry.addData(""," "); - telemetry.addData("Image", "%s (%.0f %% Conf.)", recognition.getLabel(), recognition.getConfidence() * 100); - telemetry.addData("- Position", "%.0f / %.0f", x, y); - telemetry.addData("- Size", "%.0f x %.0f", recognition.getWidth(), recognition.getHeight()); - } // end for() loop - - } // end method telemetryTfod() - -} // end class diff --git a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptTensorFlowObjectDetectionSwitchableCameras.java b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptTensorFlowObjectDetectionSwitchableCameras.java deleted file mode 100644 index 1c0ed774..00000000 --- a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptTensorFlowObjectDetectionSwitchableCameras.java +++ /dev/null @@ -1,186 +0,0 @@ -/* Copyright (c) 2020 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.robotcontroller.external.samples; - -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.ClassFactory; -import org.firstinspires.ftc.robotcore.external.hardware.camera.CameraName; -import org.firstinspires.ftc.robotcore.external.hardware.camera.WebcamName; -import org.firstinspires.ftc.robotcore.external.tfod.Recognition; -import org.firstinspires.ftc.vision.VisionPortal; -import org.firstinspires.ftc.vision.VisionPortal.CameraState; -import org.firstinspires.ftc.vision.tfod.TfodProcessor; - -import java.util.List; - -/* - * This OpMode illustrates the basics of TensorFlow Object Detection, using - * two webcams. - * - * 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. - */ -@TeleOp(name = "Concept: TensorFlow Object Detection Switchable Cameras", group = "Concept") -@Disabled -public class ConceptTensorFlowObjectDetectionSwitchableCameras extends LinearOpMode { - - /** - * Variables used for switching cameras. - */ - private WebcamName webcam1, webcam2; - private boolean oldLeftBumper; - private boolean oldRightBumper; - - /** - * The variable to store our instance of the TensorFlow Object Detection processor. - */ - private TfodProcessor tfod; - - /** - * The variable to store our instance of the vision portal. - */ - private VisionPortal visionPortal; - - @Override - public void runOpMode() { - - initTfod(); - - // Wait for the DS start button to be touched. - telemetry.addData("DS preview on/off", "3 dots, Camera Stream"); - telemetry.addData(">", "Touch Play to start OpMode"); - telemetry.update(); - waitForStart(); - - if (opModeIsActive()) { - while (opModeIsActive()) { - - telemetryCameraSwitching(); - telemetryTfod(); - - // Push telemetry to the Driver Station. - telemetry.update(); - - // Save CPU resources; can resume streaming when needed. - if (gamepad1.dpad_down) { - visionPortal.stopStreaming(); - } else if (gamepad1.dpad_up) { - visionPortal.resumeStreaming(); - } - - doCameraSwitching(); - - // Share the CPU. - sleep(20); - } - } - - // Save more CPU resources when camera is no longer needed. - visionPortal.close(); - - } // end runOpMode() - - /** - * Initialize the TensorFlow Object Detection processor. - */ - private void initTfod() { - - // Create the TensorFlow processor by using a builder. - tfod = new TfodProcessor.Builder().build(); - - webcam1 = hardwareMap.get(WebcamName.class, "Webcam 1"); - webcam2 = hardwareMap.get(WebcamName.class, "Webcam 2"); - CameraName switchableCamera = ClassFactory.getInstance() - .getCameraManager().nameForSwitchableCamera(webcam1, webcam2); - - // Create the vision portal by using a builder. - visionPortal = new VisionPortal.Builder() - .setCamera(switchableCamera) - .addProcessor(tfod) - .build(); - - } // end method initTfod() - - /** - * Add telemetry about camera switching. - */ - private void telemetryCameraSwitching() { - if (visionPortal.getActiveCamera().equals(webcam1)) { - telemetry.addData("activeCamera", "Webcam 1"); - telemetry.addData("Press RightBumper", "to switch to Webcam 2"); - } else { - telemetry.addData("activeCamera", "Webcam 2"); - telemetry.addData("Press LeftBumper", "to switch to Webcam 1"); - } - } // end method telemetryCameraSwitching() - - /** - * Add telemetry about TensorFlow Object Detection (TFOD) recognitions. - */ - private void telemetryTfod() { - - List currentRecognitions = tfod.getRecognitions(); - telemetry.addData("# Objects Detected", currentRecognitions.size()); - - // Step through the list of recognitions and display info for each one. - for (Recognition recognition : currentRecognitions) { - double x = (recognition.getLeft() + recognition.getRight()) / 2 ; - double y = (recognition.getTop() + recognition.getBottom()) / 2 ; - - telemetry.addData(""," "); - telemetry.addData("Image", "%s (%.0f %% Conf.)", recognition.getLabel(), recognition.getConfidence() * 100); - telemetry.addData("- Position", "%.0f / %.0f", x, y); - telemetry.addData("- Size", "%.0f x %.0f", recognition.getWidth(), recognition.getHeight()); - } // end for() loop - - } // end method telemetryTfod() - - /** - * Set the active camera according to input from the gamepad. - */ - private void doCameraSwitching() { - if (visionPortal.getCameraState() == CameraState.STREAMING) { - // If the left bumper is pressed, use Webcam 1. - // If the right bumper is pressed, use Webcam 2. - boolean newLeftBumper = gamepad1.left_bumper; - boolean newRightBumper = gamepad1.right_bumper; - if (newLeftBumper && !oldLeftBumper) { - visionPortal.setActiveCamera(webcam1); - } else if (newRightBumper && !oldRightBumper) { - visionPortal.setActiveCamera(webcam2); - } - oldLeftBumper = newLeftBumper; - oldRightBumper = newRightBumper; - } - } // end method doCameraSwitching() - -} // end class diff --git a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptVisionColorLocator.java b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptVisionColorLocator.java new file mode 100644 index 00000000..987694db --- /dev/null +++ b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptVisionColorLocator.java @@ -0,0 +1,191 @@ +/* + * 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 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); + } + } +} diff --git a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptVisionColorSensor.java b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptVisionColorSensor.java new file mode 100644 index 00000000..6be2bc4e --- /dev/null +++ b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/ConceptVisionColorSensor.java @@ -0,0 +1,136 @@ +/* + * 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); + } + } +} diff --git a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/RobotAutoDriveByEncoder_Linear.java b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/RobotAutoDriveByEncoder_Linear.java index 666ee2cf..b8493609 100644 --- a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/RobotAutoDriveByEncoder_Linear.java +++ b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/RobotAutoDriveByEncoder_Linear.java @@ -110,7 +110,7 @@ public void runOpMode() { rightDrive.getCurrentPosition()); telemetry.update(); - // Wait for the game to start (driver presses PLAY) + // Wait for the game to start (driver presses START) waitForStart(); // Step through each leg of the path, diff --git a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/RobotAutoDriveByGyro_Linear.java b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/RobotAutoDriveByGyro_Linear.java index 7885fe4b..ab709344 100644 --- a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/RobotAutoDriveByGyro_Linear.java +++ b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/RobotAutoDriveByGyro_Linear.java @@ -65,7 +65,7 @@ * Notes: * * All angles are referenced to the coordinate-frame that is set whenever resetHeading() is called. - * In this sample, the heading is reset when the Start button is touched on the Driver station. + * In this sample, the heading is reset when the Start button is touched on the Driver Station. * Note: It would be possible to reset the heading after each move, but this would accumulate steering errors. * * The angle of movement/rotation is assumed to be a standardized rotation around the robot Z axis, @@ -124,15 +124,15 @@ public class RobotAutoDriveByGyro_Linear extends LinearOpMode { // These constants define the desired driving/control characteristics // They can/should be tweaked to suit the specific robot drive train. static final double DRIVE_SPEED = 0.4; // Max driving speed for better distance accuracy. - static final double TURN_SPEED = 0.2; // Max Turn speed to limit turn rate + static final double TURN_SPEED = 0.2; // Max turn speed to limit turn rate. static final double HEADING_THRESHOLD = 1.0 ; // How close must the heading get to the target before moving to next step. // Requiring more accuracy (a smaller number) will often make the turn take longer to get into the final position. // Define the Proportional control coefficient (or GAIN) for "heading control". // We define one value when Turning (larger errors), and the other is used when Driving straight (smaller errors). - // Increase these numbers if the heading does not corrects strongly enough (eg: a heavy robot or using tracks) + // Increase these numbers if the heading does not correct strongly enough (eg: a heavy robot or using tracks) // Decrease these numbers if the heading does not settle on the correct value (eg: very agile robot with omni wheels) - static final double P_TURN_GAIN = 0.02; // Larger is more responsive, but also less stable - static final double P_DRIVE_GAIN = 0.03; // Larger is more responsive, but also less stable + static final double P_TURN_GAIN = 0.02; // Larger is more responsive, but also less stable. + static final double P_DRIVE_GAIN = 0.03; // Larger is more responsive, but also less stable. @Override @@ -317,7 +317,7 @@ public void turnToHeading(double maxTurnSpeed, double heading) { *

* Move will stop once the requested time has elapsed *

- * This function is useful for giving the robot a moment to stabilize it's heading between movements. + * This function is useful for giving the robot a moment to stabilize its heading between movements. * * @param maxTurnSpeed Maximum differential turn speed (range 0 to +1.0) * @param heading Absolute Heading Angle (in Degrees) relative to last gyro reset. diff --git a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/RobotAutoDriveByTime_Linear.java b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/RobotAutoDriveByTime_Linear.java index 8e09054b..6ec89fce 100644 --- a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/RobotAutoDriveByTime_Linear.java +++ b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/RobotAutoDriveByTime_Linear.java @@ -85,10 +85,10 @@ public void runOpMode() { telemetry.addData("Status", "Ready to run"); // telemetry.update(); - // Wait for the game to start (driver presses PLAY) + // Wait for the game to start (driver presses START) waitForStart(); - // Step through each leg of the path, ensuring that the Auto mode has not been stopped along the way + // Step through each leg of the path, ensuring that the OpMode has not been stopped along the way. // Step 1: Drive forward for 3 seconds leftDrive.setPower(FORWARD_SPEED); diff --git a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/RobotAutoDriveToAprilTagOmni.java b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/RobotAutoDriveToAprilTagOmni.java index 9a98f1e9..dfcf4cee 100644 --- a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/RobotAutoDriveToAprilTagOmni.java +++ b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/RobotAutoDriveToAprilTagOmni.java @@ -64,7 +64,7 @@ * The code assumes a Robot Configuration with motors named: leftfront_drive and rightfront_drive, leftback_drive and rightback_drive. * The motor directions must be set so a positive power goes forward on all wheels. * This sample assumes that the current game AprilTag Library (usually for the current season) is being loaded by default, - * so you should choose to approach a valid tag ID (usually starting at 0) + * so you should choose to approach a valid tag ID. * * Under manual control, the left stick will move forward/back & left/right. The right stick will rotate the robot. * Manually drive the robot until it displays Target data on the Driver Station. @@ -95,12 +95,12 @@ public class RobotAutoDriveToAprilTagOmni extends LinearOpMode // Set the GAIN constants to control the relationship between the measured position error, and how much power is // applied to the drive motors to correct the error. // Drive = Error * Gain Make these values smaller for smoother control, or larger for a more aggressive response. - final double SPEED_GAIN = 0.02 ; // Forward Speed Control "Gain". eg: Ramp up to 50% power at a 25 inch error. (0.50 / 25.0) - final double STRAFE_GAIN = 0.015 ; // Strafe Speed Control "Gain". eg: Ramp up to 25% power at a 25 degree Yaw error. (0.25 / 25.0) - final double TURN_GAIN = 0.01 ; // Turn Control "Gain". eg: Ramp up to 25% power at a 25 degree error. (0.25 / 25.0) + final double SPEED_GAIN = 0.02 ; // Forward Speed Control "Gain". e.g. Ramp up to 50% power at a 25 inch error. (0.50 / 25.0) + final double STRAFE_GAIN = 0.015 ; // Strafe Speed Control "Gain". e.g. Ramp up to 37% power at a 25 degree Yaw error. (0.375 / 25.0) + final double TURN_GAIN = 0.01 ; // Turn Control "Gain". e.g. Ramp up to 25% power at a 25 degree error. (0.25 / 25.0) final double MAX_AUTO_SPEED = 0.5; // Clip the approach speed to this max value (adjust for your robot) - final double MAX_AUTO_STRAFE= 0.5; // Clip the approach speed to this max value (adjust for your robot) + final double MAX_AUTO_STRAFE= 0.5; // Clip the strafing speed to this max value (adjust for your robot) final double MAX_AUTO_TURN = 0.3; // Clip the turn speed to this max value (adjust for your robot) private DcMotor leftFrontDrive = null; // Used to control the left front drive wheel @@ -145,7 +145,7 @@ public class RobotAutoDriveToAprilTagOmni extends LinearOpMode // Wait for driver to press start telemetry.addData("Camera preview on/off", "3 dots, Camera Stream"); - telemetry.addData(">", "Touch Play to start OpMode"); + telemetry.addData(">", "Touch START to start OpMode"); telemetry.update(); waitForStart(); @@ -259,7 +259,7 @@ private void initAprilTag() { aprilTag = new AprilTagProcessor.Builder().build(); // Adjust Image Decimation to trade-off detection-range for detection-rate. - // eg: Some typical detection data using a Logitech C920 WebCam + // e.g. Some typical detection data using a Logitech C920 WebCam // Decimation = 1 .. Detect 2" Tag from 10 feet away at 10 Frames per second // Decimation = 2 .. Detect 2" Tag from 6 feet away at 22 Frames per second // Decimation = 3 .. Detect 2" Tag from 4 feet away at 30 Frames Per Second diff --git a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/RobotAutoDriveToAprilTagTank.java b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/RobotAutoDriveToAprilTagTank.java index dbc1502b..1de5b9e1 100644 --- a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/RobotAutoDriveToAprilTagTank.java +++ b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/RobotAutoDriveToAprilTagTank.java @@ -63,7 +63,7 @@ * The code assumes a Robot Configuration with motors named left_drive and right_drive. * The motor directions must be set so a positive power goes forward on both wheels; * This sample assumes that the default AprilTag Library (usually for the current season) is being loaded by default - * so you should choose to approach a valid tag ID (usually starting at 0) + * so you should choose to approach a valid tag ID. * * Under manual control, the left stick will move forward/back, and the right stick will rotate the robot. * This is called POV Joystick mode, different than Tank Drive (where each joystick controls a wheel). @@ -94,8 +94,8 @@ public class RobotAutoDriveToAprilTagTank extends LinearOpMode // Set the GAIN constants to control the relationship between the measured position error, and how much power is // applied to the drive motors to correct the error. // Drive = Error * Gain Make these values smaller for smoother control, or larger for a more aggressive response. - final double SPEED_GAIN = 0.02 ; // Speed Control "Gain". eg: Ramp up to 50% power at a 25 inch error. (0.50 / 25.0) - final double TURN_GAIN = 0.01 ; // Turn Control "Gain". eg: Ramp up to 25% power at a 25 degree error. (0.25 / 25.0) + final double SPEED_GAIN = 0.02 ; // Speed Control "Gain". e.g. Ramp up to 50% power at a 25 inch error. (0.50 / 25.0) + final double TURN_GAIN = 0.01 ; // Turn Control "Gain". e.g. Ramp up to 25% power at a 25 degree error. (0.25 / 25.0) final double MAX_AUTO_SPEED = 0.5; // Clip the approach speed to this max value (adjust for your robot) final double MAX_AUTO_TURN = 0.25; // Clip the turn speed to this max value (adjust for your robot) @@ -135,7 +135,7 @@ public class RobotAutoDriveToAprilTagTank extends LinearOpMode // Wait for the driver to press Start telemetry.addData("Camera preview on/off", "3 dots, Camera Stream"); - telemetry.addData(">", "Touch Play to start OpMode"); + telemetry.addData(">", "Touch START to start OpMode"); telemetry.update(); waitForStart(); @@ -234,7 +234,7 @@ private void initAprilTag() { aprilTag = new AprilTagProcessor.Builder().build(); // Adjust Image Decimation to trade-off detection-range for detection-rate. - // eg: Some typical detection data using a Logitech C920 WebCam + // e.g. Some typical detection data using a Logitech C920 WebCam // Decimation = 1 .. Detect 2" Tag from 10 feet away at 10 Frames per second // Decimation = 2 .. Detect 2" Tag from 6 feet away at 22 Frames per second // Decimation = 3 .. Detect 2" Tag from 4 feet away at 30 Frames Per Second diff --git a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/RobotAutoDriveToLine_Linear.java b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/RobotAutoDriveToLine_Linear.java index e5076c0a..780f2604 100644 --- a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/RobotAutoDriveToLine_Linear.java +++ b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/RobotAutoDriveToLine_Linear.java @@ -106,7 +106,7 @@ public void runOpMode() { // A gain of 15 causes a Rev Color Sensor V2 to produce an Alpha value of 1.0 at about 1.5" above the floor. colorSensor.setGain(15); - // Wait for driver to press PLAY) + // Wait for driver to press START) // Abort this loop is started or stopped. while (opModeInInit()) { diff --git a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/RobotTeleopPOV_Linear.java b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/RobotTeleopPOV_Linear.java index 454d5a7c..af3840d3 100644 --- a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/RobotTeleopPOV_Linear.java +++ b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/RobotTeleopPOV_Linear.java @@ -96,10 +96,10 @@ public void runOpMode() { rightClaw.setPosition(MID_SERVO); // Send telemetry message to signify robot waiting; - telemetry.addData(">", "Robot Ready. Press Play."); // + telemetry.addData(">", "Robot Ready. Press START."); // telemetry.update(); - // Wait for the game to start (driver presses PLAY) + // Wait for the game to start (driver presses START) waitForStart(); // run until the end of the match (driver presses STOP) diff --git a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/RobotTeleopTank_Iterative.java b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/RobotTeleopTank_Iterative.java index b9f4fcff..a622f27b 100644 --- a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/RobotTeleopTank_Iterative.java +++ b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/RobotTeleopTank_Iterative.java @@ -94,25 +94,25 @@ public void init() { rightClaw.setPosition(MID_SERVO); // Send telemetry message to signify robot waiting; - telemetry.addData(">", "Robot Ready. Press Play."); // + telemetry.addData(">", "Robot Ready. Press START."); // } /* - * Code to run REPEATEDLY after the driver hits INIT, but before they hit PLAY + * Code to run REPEATEDLY after the driver hits INIT, but before they hit START */ @Override public void init_loop() { } /* - * Code to run ONCE when the driver hits PLAY + * Code to run ONCE when the driver hits START */ @Override public void start() { } /* - * Code to run REPEATEDLY after the driver hits PLAY but before they hit STOP + * Code to run REPEATEDLY after the driver hits START but before they hit STOP */ @Override public void loop() { diff --git a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/SensorDigitalTouch.java b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/SensorDigitalTouch.java new file mode 100644 index 00000000..44c3ca9c --- /dev/null +++ b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/SensorDigitalTouch.java @@ -0,0 +1,78 @@ +/* Copyright (c) 2024 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.robotcontroller.external.samples; + +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.DigitalChannel; + +/* + * This OpMode demonstrates how to use a digital channel. + * + * The OpMode assumes that the digital channel is configured with a name of "digitalTouch". + * + * 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. + */ +@TeleOp(name = "Sensor: digital channel", group = "Sensor") +@Disabled +public class SensorDigitalTouch extends LinearOpMode { + DigitalChannel digitalTouch; // Digital channel Object + + @Override + public void runOpMode() { + + // get a reference to our touchSensor object. + digitalTouch = hardwareMap.get(DigitalChannel.class, "digitalTouch"); + + digitalTouch.setMode(DigitalChannel.Mode.INPUT); + telemetry.addData("DigitalTouchSensorExample", "Press start to continue..."); + telemetry.update(); + + // wait for the start button to be pressed. + waitForStart(); + + // while the OpMode is active, loop and read the digital channel. + // Note we use opModeIsActive() as our loop condition because it is an interruptible method. + while (opModeIsActive()) { + + // button is pressed if value returned is LOW or false. + // send the info back to driver station using telemetry function. + if (digitalTouch.getState() == false) { + telemetry.addData("Button", "PRESSED"); + } else { + telemetry.addData("Button", "NOT PRESSED"); + } + + telemetry.update(); + } + } +} diff --git a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/SensorHuskyLens.java b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/SensorHuskyLens.java index 1ec1f558..af7ca552 100644 --- a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/SensorHuskyLens.java +++ b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/SensorHuskyLens.java @@ -33,13 +33,10 @@ are permitted (subject to the limitations in the disclaimer below) provided that package org.firstinspires.ftc.robotcontroller.external.samples; import com.qualcomm.hardware.dfrobot.HuskyLens; -import com.qualcomm.hardware.rev.Rev2mDistanceSensor; 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.DistanceSensor; -import org.firstinspires.ftc.robotcore.external.navigation.DistanceUnit; import org.firstinspires.ftc.robotcore.internal.system.Deadline; import java.util.concurrent.TimeUnit; @@ -51,6 +48,9 @@ are permitted (subject to the limitations in the disclaimer below) provided that * detect a number of predefined objects and AprilTags in the 36h11 family, can * recognize colors, and can be trained to detect custom objects. See this website for * documentation: https://wiki.dfrobot.com/HUSKYLENS_V1.0_SKU_SEN0305_SEN0336 + * + * For detailed instructions on how a HuskyLens is used in FTC, please see this tutorial: + * https://ftc-docs.firstinspires.org/en/latest/devices/huskylens/huskylens.html * * This sample illustrates how to detect AprilTags, but can be used to detect other types * of objects by changing the algorithm. It assumes that the HuskyLens is configured with @@ -110,6 +110,8 @@ public void runOpMode() * Users, should, in general, explicitly choose the algorithm they want to use * within the OpMode by calling selectAlgorithm() and passing it one of the values * found in the enumeration HuskyLens.Algorithm. + * + * Other algorithm choices for FTC might be: OBJECT_RECOGNITION, COLOR_RECOGNITION or OBJECT_CLASSIFICATION. */ huskyLens.selectAlgorithm(HuskyLens.Algorithm.TAG_RECOGNITION); @@ -141,6 +143,15 @@ public void runOpMode() telemetry.addData("Block count", blocks.length); for (int i = 0; i < blocks.length; i++) { telemetry.addData("Block", blocks[i].toString()); + /* + * Here inside the FOR loop, you could save or evaluate specific info for the currently recognized Bounding Box: + * - blocks[i].width and blocks[i].height (size of box, in pixels) + * - blocks[i].left and blocks[i].top (edges of box) + * - blocks[i].x and blocks[i].y (center location) + * - blocks[i].id (Color ID) + * + * These values have Java type int (integer). + */ } telemetry.update(); diff --git a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/SensorIMUNonOrthogonal.java b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/SensorIMUNonOrthogonal.java index eb1c7ca2..70bc8d4a 100644 --- a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/SensorIMUNonOrthogonal.java +++ b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/SensorIMUNonOrthogonal.java @@ -58,7 +58,7 @@ * planes (X/Y, X/Z or Y/Z) OR that the Hub has only been rotated in a range of 90 degree increments. * * Note: if your Hub is mounted Orthogonally (on a orthogonal surface, angled at some multiple of - * 90 Degrees) then you should use the simpler SensorImuOrthogonal sample in this folder. + * 90 Degrees) then you should use the simpler SensorIMUOrthogonal sample in this folder. * * But... If your Hub is mounted Non-Orthogonally, you must specify one or more rotational angles * that transform a "Default" Hub orientation into your desired orientation. That is what is @@ -94,6 +94,9 @@ public class SensorIMUNonOrthogonal extends LinearOpMode * 1) Hub laying flat on a horizontal surface, with the Printed Logo facing UP * 2) Rotated such that the USB ports are facing forward on the robot. * + * If you are using a REV External IMU, the "Default" orientation is the same as for a REV Hub, but instead of + * the USB ports facing forward, the I2C port faces forward. + * * The order that the rotations are performed matters, so this sample shows doing them in the order X, Y, then Z. * For specifying non-orthogonal hub mounting orientations, we must temporarily use axes * defined relative to the Hub itself, instead of the usual Robot Coordinate System axes @@ -124,7 +127,7 @@ public class SensorIMUNonOrthogonal extends LinearOpMode * * To get the "Default" hub into this configuration you would just need a single rotation, but around a different axis. * 1) No rotation around the X or Y axes. - * 1) Rotate the Hub -30 degrees (Clockwise) around the Z axis, since a positive angle would be Counter Clockwise. + * 2) Rotate the Hub -30 degrees (Clockwise) around the Z axis, since a positive angle would be Counter Clockwise. * * So the X,Y,Z rotations would be 0,0,-30 * diff --git a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/SensorIMUOrthogonal.java b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/SensorIMUOrthogonal.java index d92ce3e7..af4c2028 100644 --- a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/SensorIMUOrthogonal.java +++ b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/SensorIMUOrthogonal.java @@ -55,7 +55,7 @@ * (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. + * the alternative SensorIMUNonOrthogonal sample in this folder. * * This "Orthogonal" requirement means that: * @@ -98,6 +98,9 @@ public class SensorIMUOrthogonal extends LinearOpMode * 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. diff --git a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/SensorLimelight3A.java b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/SensorLimelight3A.java new file mode 100644 index 00000000..6c1f702a --- /dev/null +++ b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/SensorLimelight3A.java @@ -0,0 +1,159 @@ +/* +Copyright (c) 2024 Limelight Vision + +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.robotcontroller.external.samples; + +import com.qualcomm.hardware.limelightvision.LLResult; +import com.qualcomm.hardware.limelightvision.LLResultTypes; +import com.qualcomm.hardware.limelightvision.LLStatus; +import com.qualcomm.hardware.limelightvision.Limelight3A; +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.Pose3D; + +import java.util.List; + +/* + * This OpMode illustrates how to use the Limelight3A Vision Sensor. + * + * @see Limelight + * + * Notes on configuration: + * + * The device presents itself, when plugged into a USB port on a Control Hub as an ethernet + * interface. A DHCP server running on the Limelight automatically assigns the Control Hub an + * ip address for the new ethernet interface. + * + * Since the Limelight is plugged into a USB port, it will be listed on the top level configuration + * activity along with the Control Hub Portal and other USB devices such as webcams. Typically + * serial numbers are displayed below the device's names. In the case of the Limelight device, the + * Control Hub's assigned ip address for that ethernet interface is used as the "serial number". + * + * Tapping the Limelight's name, transitions to a new screen where the user can rename the Limelight + * and specify the Limelight's ip address. Users should take care not to confuse the ip address of + * the Limelight itself, which can be configured through the Limelight settings page via a web browser, + * and the ip address the Limelight device assigned the Control Hub and which is displayed in small text + * below the name of the Limelight on the top level configuration screen. + */ +@TeleOp(name = "Sensor: Limelight3A", group = "Sensor") +@Disabled +public class SensorLimelight3A extends LinearOpMode { + + private Limelight3A limelight; + + @Override + public void runOpMode() throws InterruptedException + { + limelight = hardwareMap.get(Limelight3A.class, "limelight"); + + telemetry.setMsTransmissionInterval(11); + + limelight.pipelineSwitch(0); + + /* + * Starts polling for data. If you neglect to call start(), getLatestResult() will return null. + */ + limelight.start(); + + telemetry.addData(">", "Robot Ready. Press Play."); + telemetry.update(); + waitForStart(); + + while (opModeIsActive()) { + LLStatus status = limelight.getStatus(); + telemetry.addData("Name", "%s", + status.getName()); + telemetry.addData("LL", "Temp: %.1fC, CPU: %.1f%%, FPS: %d", + status.getTemp(), status.getCpu(),(int)status.getFps()); + telemetry.addData("Pipeline", "Index: %d, Type: %s", + status.getPipelineIndex(), status.getPipelineType()); + + LLResult result = limelight.getLatestResult(); + if (result != null) { + // Access general information + Pose3D botpose = result.getBotpose(); + double captureLatency = result.getCaptureLatency(); + double targetingLatency = result.getTargetingLatency(); + double parseLatency = result.getParseLatency(); + telemetry.addData("LL Latency", captureLatency + targetingLatency); + telemetry.addData("Parse Latency", parseLatency); + telemetry.addData("PythonOutput", java.util.Arrays.toString(result.getPythonOutput())); + + if (result.isValid()) { + telemetry.addData("tx", result.getTx()); + telemetry.addData("txnc", result.getTxNC()); + telemetry.addData("ty", result.getTy()); + telemetry.addData("tync", result.getTyNC()); + + telemetry.addData("Botpose", botpose.toString()); + + // Access barcode results + List barcodeResults = result.getBarcodeResults(); + for (LLResultTypes.BarcodeResult br : barcodeResults) { + telemetry.addData("Barcode", "Data: %s", br.getData()); + } + + // Access classifier results + List classifierResults = result.getClassifierResults(); + for (LLResultTypes.ClassifierResult cr : classifierResults) { + telemetry.addData("Classifier", "Class: %s, Confidence: %.2f", cr.getClassName(), cr.getConfidence()); + } + + // Access detector results + List detectorResults = result.getDetectorResults(); + for (LLResultTypes.DetectorResult dr : detectorResults) { + telemetry.addData("Detector", "Class: %s, Area: %.2f", dr.getClassName(), dr.getTargetArea()); + } + + // Access fiducial results + List fiducialResults = result.getFiducialResults(); + for (LLResultTypes.FiducialResult fr : fiducialResults) { + telemetry.addData("Fiducial", "ID: %d, Family: %s, X: %.2f, Y: %.2f", fr.getFiducialId(), fr.getFamily(),fr.getTargetXDegrees(), fr.getTargetYDegrees()); + } + + // Access color results + List colorResults = result.getColorResults(); + for (LLResultTypes.ColorResult cr : colorResults) { + telemetry.addData("Color", "X: %.2f, Y: %.2f", cr.getTargetXDegrees(), cr.getTargetYDegrees()); + } + } + } else { + telemetry.addData("Limelight", "No data available"); + } + + telemetry.update(); + } + limelight.stop(); + } +} diff --git a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/SensorOctoQuad.java b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/SensorOctoQuad.java new file mode 100644 index 00000000..f797c6b0 --- /dev/null +++ b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/SensorOctoQuad.java @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2024 DigitalChickenLabs + * + * 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 com.qualcomm.hardware.digitalchickenlabs.OctoQuad; +import com.qualcomm.robotcore.eventloop.opmode.LinearOpMode; +import com.qualcomm.robotcore.eventloop.opmode.TeleOp; +import com.qualcomm.robotcore.eventloop.opmode.Disabled; +import org.firstinspires.ftc.robotcore.external.Telemetry; + +/* + * This OpMode illustrates how to use the DigitalChickenLabs OctoQuad Quadrature Encoder & Pulse Width Interface Module + * + * The OctoQuad has 8 input channels that can used to read either Relative Quadrature Encoders or Pulse-Width Absolute Encoder inputs. + * Relative Quadrature encoders are found on most FTC motors, and some stand-alone position sensors like the REV Thru-Bore encoder. + * Pulse-Width encoders are less common. The REV Thru-Bore encoder can provide its absolute position via a variable pulse width, + * as can several sonar rangefinders such as the MaxBotix MB1000 series. + * + * This basic sample shows how an OctoQuad can be used to read the position three Odometry pods fitted + * with REV Thru-Bore encoders. For a more advanced example showing additional OctoQuad capabilities, see the SensorOctoQuadAdv sample. + * + * This OpMode assumes that the OctoQuad is attached to an I2C interface named "octoquad" in the robot configuration. + * + * The code assumes the first three OctoQuad inputs are connected as follows + * - Chan 0: for measuring forward motion on the left side of the robot. + * - Chan 1: for measuring forward motion on the right side of the robot. + * - Chan 2: for measuring Lateral (strafing) motion. + * + * The encoder values may be reset to zero by pressing the X (left most) button on Gamepad 1. + * + * This sample does not show how to interpret these readings, just how to obtain and display them. + * + * 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 + * + * See the sensor's product page: https://www.tindie.com/products/35114/ + */ +@TeleOp(name = "OctoQuad Basic", group="OctoQuad") +@Disabled +public class SensorOctoQuad extends LinearOpMode { + + // Identify which encoder OctoQuad inputs are connected to each odometry pod. + private final int ODO_LEFT = 0; // Facing forward direction on left side of robot (Axial motion) + private final int ODO_RIGHT = 1; // Facing forward direction on right side or robot (Axial motion) + private final int ODO_PERP = 2; // Facing perpendicular direction at the center of the robot (Lateral motion) + + // Declare the OctoQuad object and members to store encoder positions and velocities + private OctoQuad octoquad; + + private int posLeft; + private int posRight; + private int posPerp; + + /** + * This function is executed when this OpMode is selected from the Driver Station. + */ + @Override + public void runOpMode() { + + // Connect to OctoQuad by referring to its name in the Robot Configuration. + octoquad = hardwareMap.get(OctoQuad.class, "octoquad"); + + // Read the Firmware Revision number from the OctoQuad and display it as telemetry. + telemetry.addData("OctoQuad Firmware Version ", octoquad.getFirmwareVersion()); + + // Reverse the count-direction of any encoder that is not what you require. + // e.g. if you push the robot forward and the left encoder counts down, then reverse it so it counts up. + octoquad.setSingleEncoderDirection(ODO_LEFT, OctoQuad.EncoderDirection.REVERSE); + octoquad.setSingleEncoderDirection(ODO_RIGHT, OctoQuad.EncoderDirection.FORWARD); + octoquad.setSingleEncoderDirection(ODO_PERP, OctoQuad.EncoderDirection.FORWARD); + + // Any changes that are made should be saved in FLASH just in case there is a sensor power glitch. + octoquad.saveParametersToFlash(); + + telemetry.addLine("\nPress START to read encoder values"); + telemetry.update(); + + waitForStart(); + + // Configure the telemetry for optimal display of data. + telemetry.setDisplayFormat(Telemetry.DisplayFormat.MONOSPACE); + telemetry.setMsTransmissionInterval(50); + + // Set all the encoder inputs to zero. + octoquad.resetAllPositions(); + + // Loop while displaying the odometry pod positions. + while (opModeIsActive()) { + telemetry.addData(">", "Press X to Reset Encoders\n"); + + // Check for X button to reset encoders. + if (gamepad1.x) { + // Reset the position of all encoders to zero. + octoquad.resetAllPositions(); + } + + // Read all the encoder data. Load into local members. + readOdometryPods(); + + // Display the values. + telemetry.addData("Left ", "%8d counts", posLeft); + telemetry.addData("Right", "%8d counts", posRight); + telemetry.addData("Perp ", "%8d counts", posPerp); + telemetry.update(); + } + } + + private void readOdometryPods() { + // For best performance, we should only perform ONE transaction with the OctoQuad each cycle. + // Since this example only needs to read positions from a few channels, we could use either + // readPositionRange(idxFirst, idxLast) to get a select number of sequential channels + // or + // readAllPositions() to get all 8 encoder readings + // + // Since both calls take almost the same amount of time, and the actual channels may not end up + // being sequential, we will read all of the encoder positions, and then pick out the ones we need. + int[] positions = octoquad.readAllPositions(); + posLeft = positions[ODO_LEFT]; + posRight = positions[ODO_RIGHT]; + posPerp = positions[ODO_PERP]; + } +} diff --git a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/SensorOctoQuadAdv.java b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/SensorOctoQuadAdv.java new file mode 100644 index 00000000..e763b9aa --- /dev/null +++ b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/SensorOctoQuadAdv.java @@ -0,0 +1,278 @@ +/* + * Copyright (c) 2024 DigitalChickenLabs + * + * 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 com.qualcomm.hardware.digitalchickenlabs.OctoQuad; +import com.qualcomm.hardware.digitalchickenlabs.OctoQuadBase; +import com.qualcomm.robotcore.eventloop.opmode.LinearOpMode; +import com.qualcomm.robotcore.eventloop.opmode.TeleOp; +import com.qualcomm.robotcore.util.ElapsedTime; +import com.qualcomm.robotcore.util.MovingStatistics; +import com.qualcomm.robotcore.eventloop.opmode.Disabled; + + +import org.firstinspires.ftc.robotcore.external.Telemetry; +import org.firstinspires.ftc.robotcore.external.navigation.AngleUnit; + +import java.util.ArrayList; +import java.util.List; + +/* + * This OpMode illustrates how to use advanced features of the DigitalChickenLabs OctoQuad Quadrature Encoder & Pulse Width Interface Module + * + * The OctoQuad has 8 input channels that can used to read either Quadrature Encoder signals (like with most FTC motors) + * or Pulse-Width style Absolute Encoder inputs (eg: REV Through Bore encoder pulse width output). + * + * This OpMode illustrates several of the more advanced features of an OctoQuad, including Pulse Width measurement and velocity measurement. + * For a more basic OpMode just showing how to read encoder inputs, see the SensorOctoQuad sample. + * + * This OpMode assumes that the OctoQuad is attached to an I2C interface named "octoquad" in the robot configuration. + * + * One system that requires a lot of encoder inputs is a Swerve Drive system. + * Such a drive requires two encoders per drive module: one for position & velocity of the Drive motor/wheel, and one for position/angle of the Steering motor. + * The Drive motor usually requires a quadrature encoder, and the Steering motor requires an Absolute encoder. + * This quantity and combination of encoder inputs is a challenge, but a single OctoQuad could be used to read them all. + * + * This sample will configure an OctoQuad for a swerve drive, as follows + * - Configure 4 Relative Quadrature Encoder inputs and 4 Absolute Pulse-Width Encoder inputs + * - Configure a velocity sample interval of 25 mSec + * - Configure a pulse width input range of 1-1024 uSec for a REV Through Bore Encoder's Absolute Pulse output. + * + * An OctoSwerveDrive class will be created to initialize the OctoQuad, and manage the 4 swerve modules. + * An OctoSwerveModule class will be created to configure and read a single swerve module. + * + * Wiring: + * The OctoQuad will be configured to accept Quadrature encoders on the first four channels and Absolute (pulse width) encoders on the last four channels. + * + * The standard 4-pin to 4-pin cable can be used to connect each Driver Motor encoder to the OctoQuad. (channels 0-3) + * + * A modified version of the REV 6-4 pin cable (shipped with the encoder) connects the steering encoder to the OctoQuad. (channels 4-7) + * To connect the Absolute position signal from a REV Thru-Bore encoder to the OctoQuad, the Provided 6-pin to 4-pin cable will need to be modified. + * At the 6-pin connector end, move the yellow wire from its initial pin-3 position to the ABS pin-5 position. This can be done easily + * by using a small flathead screwdriver to lift the small white tab holding the metal wire crimp in place and gently pulling the wire out. + * See the OctoSwerveDrive() constructor below for the correct wheel/channel assignment. + * + * 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 + * + * Note: If you prefer, you can move the two support classes from this file, and place them in their own files. + * But leaving them in place is simpler for this example. + * + * See the sensor's product page: https://www.tindie.com/products/35114/ + */ +@TeleOp(name="OctoQuad Advanced", group="OctoQuad") +@Disabled +public class SensorOctoQuadAdv extends LinearOpMode { + + @Override + public void runOpMode() throws InterruptedException { + // Connect to the OctoQuad by looking up its name in the hardwareMap. + OctoQuad octoquad = hardwareMap.get(OctoQuad.class, "octoquad"); + + // Create the interface for the Swerve Drive Encoders + OctoSwerveDrive octoSwerveDrive = new OctoSwerveDrive(octoquad); + + // Display the OctoQuad firmware revision + telemetry.addLine("OctoQuad Firmware v" + octoquad.getFirmwareVersion()); + telemetry.addLine("\nPress START to read encoder values"); + telemetry.update(); + + waitForStart(); + + // Configure the telemetry for optimal display of data. + telemetry.setDisplayFormat(Telemetry.DisplayFormat.MONOSPACE); + telemetry.setMsTransmissionInterval(50); + + // Run stats to determine cycle times. + MovingStatistics avgTime = new MovingStatistics(100); + ElapsedTime elapsedTime = new ElapsedTime(); + + while (opModeIsActive()) { + telemetry.addData(">", "Press X to Reset Encoders\n"); + + if(gamepad1.x) { + octoquad.resetAllPositions(); + } + + // read all the swerve drive encoders and update positions and velocities. + octoSwerveDrive.updateModules(); + octoSwerveDrive.show(telemetry); + + // Update cycle time stats + avgTime.add(elapsedTime.nanoseconds()); + elapsedTime.reset(); + + telemetry.addData("Loop time", "%.1f mS", avgTime.getMean()/1000000); + telemetry.update(); + } + } +} + +// ============================ Internal (Inner) Classes ============================= + +/*** + * OctoSwerveDrive class manages 4 Swerve Modules + * - Performs general OctoQuad initialization + * - Creates 4 module classes, one for each swerve module + * - Updates swerve drive status by reading all data from OctoQuad and Updating each module + * - Displays all swerve drive data as telemetry + */ +class OctoSwerveDrive { + + private final OctoQuad octoquad; + private final List allModules = new ArrayList<>(); + + // members to hold encoder data for each module. + public final OctoSwerveModule LeftFront; + public final OctoSwerveModule RightFront; + public final OctoSwerveModule LeftBack; + public final OctoSwerveModule RightBack; + + // Prepare an object to hold an entire OctoQuad encoder readable register bank (pos and vel) + private final OctoQuad.EncoderDataBlock encoderDataBlock = new OctoQuad.EncoderDataBlock(); + + public OctoSwerveDrive(OctoQuad octoquad) { + this.octoquad = octoquad; + + // Clear out all prior settings and encoder data before setting up desired configuration + octoquad.resetEverything(); + + // Assume first 4 channels are relative encoders and the next 4 are absolute encoders + octoquad.setChannelBankConfig(OctoQuad.ChannelBankConfig.BANK1_QUADRATURE_BANK2_PULSE_WIDTH); + + // Create the four OctoSwerveModules, and add them to a 'list' for easier reference. + + // Note: The wheel/channel order is set here. Ensure your encoder cables match. + // + // Note: The angleOffset must be set for each module so a forward facing wheel shows a steer angle of 0 degrees. + // The process for determining the correct angleOffsets is as follows: + // 1) Set all the angleValues (below) to zero then build and deploy the code. + // 2) Physically rotate all the swerve drives so the wheels are facing forward in the desired 0 degree position + // 3) Run the OpMode, view the telemetry and record the "Degrees" value for each module. + // 4) Update the code by entering the recorded Degrees value for each module as the angleOffset (last) parameter in the lines below. + // + // Rebuild and deploy the new code. Verify that the telemetry now indicates 0 degrees when the wheels are facing forward. + // Also verify that the correct module values change appropriately when you manually spin (drive) and rotate (steer) a wheel. + + allModules.add(LeftFront = new OctoSwerveModule(octoquad, "LF ",0,0));// Drive = 0, Steer = 4 + allModules.add(RightFront = new OctoSwerveModule(octoquad, "RF ",1,0));// Drive = 1, Steer = 5 + allModules.add(LeftBack = new OctoSwerveModule(octoquad, "LB ",2,0));// Drive = 2, Steer = 6 + allModules.add(RightBack = new OctoSwerveModule(octoquad, "RB ",3,0));// Drive = 3, Steer = 7 + + // now make sure the settings persist through any power glitches. + octoquad.saveParametersToFlash(); + } + + /** + * Updates all 4 swerve modules + */ + public void updateModules() { + // Read full OctoQuad data block and then pass DataBlock to each swerve module to update themselves. + octoquad.readAllEncoderData(encoderDataBlock); + for (OctoSwerveModule module : allModules) { + module.updateModule(encoderDataBlock); + } + } + + /** + * Generate telemetry data for all modules. + * @param telemetry OpMode Telemetry object + */ + public void show(Telemetry telemetry) { + // create general header block and then have each module add its own telemetry + telemetry.addData("pos", " Count CPS Degree DPS"); + for (OctoSwerveModule module : allModules) { + module.show(telemetry); + } + } +} + +/*** + * The OctoSwerveModule class manages a single swerve module + */ +class OctoSwerveModule { + + public double driveCounts; + public double driveCountsPerSec; + public double steerDegrees; + public double steerDegreesPerSec; + + private final String name; + private final int channel; + private final double angleOffset; + private final double steerDirMult; + + private static final int VELOCITY_SAMPLE_INTERVAL_MS = 25; // To provide 40 updates per second. + private static final double DEGREES_PER_US = (360.0 / 1024.0); // based on REV Through Bore Encoder + private static final double VELOCITY_SAMPLES_PER_S = (1000.0 / VELOCITY_SAMPLE_INTERVAL_MS); + + // The correct drive and turn directions must be set for the Swerve Module based on the specific hardware geometry. + // Forward motion must generate an increasing drive count. + // Counter Clockwise steer rotation must generate an increasing Steer Angle (degrees) + private static final boolean INVERT_DRIVE_ENCODER = false; // Set true if forward motion decreases drive "Count" + private static final boolean INVERT_STEER_ENCODER = false; // Set true if counter clockwise steer action decreases steer "Degree" + + /*** + * @param octoquad provide access to configure OctoQuad + * @param name name used for telemetry display + * @param quadChannel Quadrature encoder channel. Pulse Width channel is this + 4 + * @param angleOffset Angle to subtract from absolute encoder to calibrate zero position. (see comments above) + */ + public OctoSwerveModule (OctoQuad octoquad, String name, int quadChannel, double angleOffset) { + this.name = name; + this.channel = quadChannel; + this.angleOffset = angleOffset; + this.steerDirMult = INVERT_STEER_ENCODER ? -1 : 1 ; // create a multiplier to flip the steer angle. + + // Set the drive encoder direction. Note the absolute encoder does not have built-in direction inversion. + octoquad.setSingleEncoderDirection(channel, INVERT_DRIVE_ENCODER ? OctoQuad.EncoderDirection.REVERSE : OctoQuad.EncoderDirection.FORWARD); + + // Set the velocity sample interval on both encoders + octoquad.setSingleVelocitySampleInterval(channel, VELOCITY_SAMPLE_INTERVAL_MS); + octoquad.setSingleVelocitySampleInterval(channel + 4, VELOCITY_SAMPLE_INTERVAL_MS); + + // Setup Absolute encoder pulse range to match REV Through Bore encoder. + octoquad.setSingleChannelPulseWidthParams (channel + 4, new OctoQuad.ChannelPulseWidthParams(1,1024)); + } + + /*** + * Calculate the Swerve module's position and velocity values + * @param encoderDataBlock most recent full data block read from OctoQuad. + */ + public void updateModule(OctoQuad.EncoderDataBlock encoderDataBlock) { + driveCounts = encoderDataBlock.positions[channel]; // get Counts. + driveCountsPerSec = encoderDataBlock.velocities[channel] * VELOCITY_SAMPLES_PER_S; // convert counts/interval to counts/sec + + // convert uS to degrees. Add in any possible direction flip. + steerDegrees = AngleUnit.normalizeDegrees((encoderDataBlock.positions[channel+ 4] * DEGREES_PER_US * steerDirMult) - angleOffset); + // convert uS/interval to deg per sec. Add in any possible direction flip. + steerDegreesPerSec = encoderDataBlock.velocities[channel + 4] * DEGREES_PER_US * steerDirMult * VELOCITY_SAMPLES_PER_S; + } + + /** + * Display the Swerve module's state as telemetry + * @param telemetry OpMode Telemetry object + */ + public void show(Telemetry telemetry) { + telemetry.addData(name, "%8.0f %7.0f %7.0f %6.0f", driveCounts, driveCountsPerSec, steerDegrees, steerDegreesPerSec); + } +} diff --git a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/SensorSparkFunOTOS.java b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/SensorSparkFunOTOS.java new file mode 100644 index 00000000..3a25230f --- /dev/null +++ b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/SensorSparkFunOTOS.java @@ -0,0 +1,156 @@ +/* + SPDX-License-Identifier: MIT + + Copyright (c) 2024 SparkFun Electronics +*/ +package org.firstinspires.ftc.robotcontroller.external.samples; + +import com.qualcomm.robotcore.eventloop.opmode.Disabled; +import com.qualcomm.robotcore.eventloop.opmode.LinearOpMode; +import com.qualcomm.robotcore.eventloop.opmode.TeleOp; + +import com.qualcomm.hardware.sparkfun.SparkFunOTOS; + +import org.firstinspires.ftc.robotcore.external.navigation.AngleUnit; +import org.firstinspires.ftc.robotcore.external.navigation.DistanceUnit; + +/* + * This OpMode illustrates how to use the SparkFun Qwiic Optical Tracking Odometry Sensor (OTOS) + * + * The OpMode assumes that the sensor is configured with a name of "sensor_otos". + * + * 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 + * + * See the sensor's product page: https://www.sparkfun.com/products/24904 + */ +@TeleOp(name = "Sensor: SparkFun OTOS", group = "Sensor") +@Disabled +public class SensorSparkFunOTOS extends LinearOpMode { + // Create an instance of the sensor + SparkFunOTOS myOtos; + + @Override + public void runOpMode() throws InterruptedException { + // Get a reference to the sensor + myOtos = hardwareMap.get(SparkFunOTOS.class, "sensor_otos"); + + // All the configuration for the OTOS is done in this helper method, check it out! + configureOtos(); + + // Wait for the start button to be pressed + waitForStart(); + + // Loop until the OpMode ends + while (opModeIsActive()) { + // Get the latest position, which includes the x and y coordinates, plus the + // heading angle + SparkFunOTOS.Pose2D pos = myOtos.getPosition(); + + // Reset the tracking if the user requests it + if (gamepad1.y) { + myOtos.resetTracking(); + } + + // Re-calibrate the IMU if the user requests it + if (gamepad1.x) { + myOtos.calibrateImu(); + } + + // Inform user of available controls + telemetry.addLine("Press Y (triangle) on Gamepad to reset tracking"); + telemetry.addLine("Press X (square) on Gamepad to calibrate the IMU"); + telemetry.addLine(); + + // Log the position to the telemetry + telemetry.addData("X coordinate", pos.x); + telemetry.addData("Y coordinate", pos.y); + telemetry.addData("Heading angle", pos.h); + + // Update the telemetry on the driver station + telemetry.update(); + } + } + + private void configureOtos() { + telemetry.addLine("Configuring OTOS..."); + telemetry.update(); + + // Set the desired units for linear and angular measurements. Can be either + // meters or inches for linear, and radians or degrees for angular. If not + // set, the default is inches and degrees. Note that this setting is not + // persisted in the sensor, so you need to set at the start of all your + // OpModes if using the non-default value. + // myOtos.setLinearUnit(DistanceUnit.METER); + myOtos.setLinearUnit(DistanceUnit.INCH); + // myOtos.setAngularUnit(AnguleUnit.RADIANS); + myOtos.setAngularUnit(AngleUnit.DEGREES); + + // Assuming you've mounted your sensor to a robot and it's not centered, + // you can specify the offset for the sensor relative to the center of the + // robot. The units default to inches and degrees, but if you want to use + // different units, specify them before setting the offset! Note that as of + // firmware version 1.0, these values will be lost after a power cycle, so + // you will need to set them each time you power up the sensor. For example, if + // the sensor is mounted 5 inches to the left (negative X) and 10 inches + // forward (positive Y) of the center of the robot, and mounted 90 degrees + // clockwise (negative rotation) from the robot's orientation, the offset + // would be {-5, 10, -90}. These can be any value, even the angle can be + // tweaked slightly to compensate for imperfect mounting (eg. 1.3 degrees). + SparkFunOTOS.Pose2D offset = new SparkFunOTOS.Pose2D(0, 0, 0); + myOtos.setOffset(offset); + + // Here we can set the linear and angular scalars, which can compensate for + // scaling issues with the sensor measurements. Note that as of firmware + // version 1.0, these values will be lost after a power cycle, so you will + // need to set them each time you power up the sensor. They can be any value + // from 0.872 to 1.127 in increments of 0.001 (0.1%). It is recommended to + // first set both scalars to 1.0, then calibrate the angular scalar, then + // the linear scalar. To calibrate the angular scalar, spin the robot by + // multiple rotations (eg. 10) to get a precise error, then set the scalar + // to the inverse of the error. Remember that the angle wraps from -180 to + // 180 degrees, so for example, if after 10 rotations counterclockwise + // (positive rotation), the sensor reports -15 degrees, the required scalar + // would be 3600/3585 = 1.004. To calibrate the linear scalar, move the + // robot a known distance and measure the error; do this multiple times at + // multiple speeds to get an average, then set the linear scalar to the + // inverse of the error. For example, if you move the robot 100 inches and + // the sensor reports 103 inches, set the linear scalar to 100/103 = 0.971 + myOtos.setLinearScalar(1.0); + myOtos.setAngularScalar(1.0); + + // The IMU on the OTOS includes a gyroscope and accelerometer, which could + // have an offset. Note that as of firmware version 1.0, the calibration + // will be lost after a power cycle; the OTOS performs a quick calibration + // when it powers up, but it is recommended to perform a more thorough + // calibration at the start of all your OpModes. Note that the sensor must + // be completely stationary and flat during calibration! When calling + // calibrateImu(), you can specify the number of samples to take and whether + // to wait until the calibration is complete. If no parameters are provided, + // it will take 255 samples and wait until done; each sample takes about + // 2.4ms, so about 612ms total + myOtos.calibrateImu(); + + // Reset the tracking algorithm - this resets the position to the origin, + // but can also be used to recover from some rare tracking errors + myOtos.resetTracking(); + + // After resetting the tracking, the OTOS will report that the robot is at + // the origin. If your robot does not start at the origin, or you have + // another source of location information (eg. vision odometry), you can set + // the OTOS location to match and it will continue to track from there. + SparkFunOTOS.Pose2D currentPosition = new SparkFunOTOS.Pose2D(0, 0, 0); + myOtos.setPosition(currentPosition); + + // Get the hardware and firmware version + SparkFunOTOS.Version hwVersion = new SparkFunOTOS.Version(); + SparkFunOTOS.Version fwVersion = new SparkFunOTOS.Version(); + myOtos.getVersionInfo(hwVersion, fwVersion); + + telemetry.addLine("OTOS configured! Press start to get position data!"); + telemetry.addLine(); + telemetry.addLine(String.format("OTOS Hardware Version: v%d.%d", hwVersion.major, hwVersion.minor)); + telemetry.addLine(String.format("OTOS Firmware Version: v%d.%d", fwVersion.major, fwVersion.minor)); + telemetry.update(); + } +} diff --git a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/UtilityOctoQuadConfigMenu.java b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/UtilityOctoQuadConfigMenu.java new file mode 100644 index 00000000..a962919f --- /dev/null +++ b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/UtilityOctoQuadConfigMenu.java @@ -0,0 +1,812 @@ +/* + * Copyright (c) 2024 DigitalChickenLabs + * + * 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 com.qualcomm.hardware.digitalchickenlabs.OctoQuad; +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.Gamepad; + +import org.firstinspires.ftc.robotcore.external.Telemetry; + +import java.util.ArrayList; +import java.util.Stack; + +/* + * This OpMode illustrates how to use the DigitalChickenLabs OctoQuad Quadrature Encoder & Pulse Width Interface Module. + * + * The OctoQuad has 8 input channels that can used to read either Relative Quadrature Encoders or Pulse-Width Absolute Encoder inputs. + * Relative Quadrature encoders are found on most FTC motors, and some stand-alone position sensors like the REV Thru-Bore encoder. + * Pulse-Width encoders are less common. The REV Thru-Bore encoder can provide its absolute position via a variable pulse width, + * as can several sonar rangefinders such as the MaxBotix MB1000 series. + * + * This OpMode assumes that the OctoQuad is attached to an I2C interface named "octoquad" in the robot configuration. + * + * Remove or comment out the @Disabled line to add this OpMode to the Driver Station OpMode list + * + * Select, Init and run the "OctoQuad Configuration Tool" OpMode + * Read the blue User-Interface tips at the top of the telemetry screen. + * Use the UI buttons to navigate the menu and make any desired changes to the OctoQuad configuration. + * Use the Program Settings To FLASH option to make any changes permanent. + * + * See the sensor's product page: https://www.tindie.com/products/digitalchickenlabs/octoquad-8ch-quadrature-pulse-width-decoder/ + */ +@TeleOp(name = "OctoQuad Configuration Tool", group="OctoQuad") +@Disabled +public class UtilityOctoQuadConfigMenu extends LinearOpMode +{ + TelemetryMenu.MenuElement rootMenu = new TelemetryMenu.MenuElement("OctoQuad Config Menu", true); + TelemetryMenu.MenuElement menuHwInfo = new TelemetryMenu.MenuElement("Hardware Information", false); + TelemetryMenu.EnumOption optionI2cResetMode; + TelemetryMenu.EnumOption optionChannelBankConfig; + + TelemetryMenu.MenuElement menuEncoderDirections = new TelemetryMenu.MenuElement("Set Encoder Directions", false); + TelemetryMenu.BooleanOption[] optionsEncoderDirections = new TelemetryMenu.BooleanOption[OctoQuad.NUM_ENCODERS]; + + TelemetryMenu.MenuElement menuVelocityIntervals = new TelemetryMenu.MenuElement("Velocity Measurement Intervals", false); + TelemetryMenu.IntegerOption[] optionsVelocityIntervals = new TelemetryMenu.IntegerOption[OctoQuad.NUM_ENCODERS]; + + TelemetryMenu.MenuElement menuAbsParams = new TelemetryMenu.MenuElement("Abs. Encoder Pulse Width Params", false); + TelemetryMenu.IntegerOption[] optionsAbsParamsMax = new TelemetryMenu.IntegerOption[OctoQuad.NUM_ENCODERS]; + TelemetryMenu.IntegerOption[] optionsAbsParamsMin = new TelemetryMenu.IntegerOption[OctoQuad.NUM_ENCODERS]; + + TelemetryMenu.OptionElement optionProgramToFlash; + TelemetryMenu.OptionElement optionSendToRAM; + + TelemetryMenu.StaticClickableOption optionExit; + + OctoQuad octoquad; + + boolean error = false; + + @Override + public void runOpMode() + { + octoquad = hardwareMap.getAll(OctoQuad.class).get(0); + + if(octoquad.getChipId() != OctoQuad.OCTOQUAD_CHIP_ID) + { + telemetry.addLine("Error: cannot communicate with OctoQuad. Check your wiring and configuration and try again"); + telemetry.update(); + + error = true; + } + else + { + if(octoquad.getFirmwareVersion().maj != OctoQuad.SUPPORTED_FW_VERSION_MAJ) + { + telemetry.addLine("Error: The OctoQuad is running a different major firmware version than this driver was built for. Cannot run configuration tool"); + telemetry.update(); + + error = true; + } + } + + if(error) + { + waitForStart(); + return; + } + + telemetry.addLine("Retrieving current configuration from OctoQuad"); + telemetry.update(); + + optionExit = new TelemetryMenu.StaticClickableOption("Exit configuration menu") + { + @Override + void onClick() // called on OpMode thread + { + requestOpModeStop(); + } + }; + + optionI2cResetMode = new TelemetryMenu.EnumOption("I2C Reset Mode", OctoQuad.I2cRecoveryMode.values(), octoquad.getI2cRecoveryMode()); + optionChannelBankConfig = new TelemetryMenu.EnumOption("Channel Bank Modes", OctoQuad.ChannelBankConfig.values(), octoquad.getChannelBankConfig()); + + menuHwInfo.addChild(new TelemetryMenu.StaticItem("Board Firmware: v" + octoquad.getFirmwareVersion())); + //menuHwInfo.addChild(new TelemetryMenu.StaticItem("Board unique ID: FIXME")); + + for(int i = 0; i < OctoQuad.NUM_ENCODERS; i++) + { + optionsEncoderDirections[i] = new TelemetryMenu.BooleanOption( + String.format("Encoder %d direction", i), + octoquad.getSingleEncoderDirection(i) == OctoQuad.EncoderDirection.REVERSE, + "-", + "+"); + } + menuEncoderDirections.addChildren(optionsEncoderDirections); + + for(int i = 0; i < OctoQuad.NUM_ENCODERS; i++) + { + optionsVelocityIntervals[i] = new TelemetryMenu.IntegerOption( + String.format("Chan %d velocity intvl", i), + OctoQuad.MIN_VELOCITY_MEASUREMENT_INTERVAL_MS, + OctoQuad.MAX_VELOCITY_MEASUREMENT_INTERVAL_MS, + octoquad.getSingleVelocitySampleInterval(i)); + } + menuVelocityIntervals.addChildren(optionsVelocityIntervals); + + for(int i = 0; i < OctoQuad.NUM_ENCODERS; i++) + { + OctoQuad.ChannelPulseWidthParams params = octoquad.getSingleChannelPulseWidthParams(i); + + optionsAbsParamsMax[i] = new TelemetryMenu.IntegerOption( + String.format("Chan %d max pulse length", i), + OctoQuad.MIN_PULSE_WIDTH_US, + OctoQuad.MAX_PULSE_WIDTH_US, + params.max_length_us); + + optionsAbsParamsMin[i] = new TelemetryMenu.IntegerOption( + String.format("Chan %d min pulse length", i), + OctoQuad.MIN_PULSE_WIDTH_US, + OctoQuad.MAX_PULSE_WIDTH_US, + params.min_length_us); + } + menuAbsParams.addChildren(optionsAbsParamsMin); + menuAbsParams.addChildren(optionsAbsParamsMax); + + optionProgramToFlash = new TelemetryMenu.OptionElement() + { + String name = "Program Settings to FLASH"; + long lastClickTime = 0; + + @Override + protected String getDisplayText() + { + if(lastClickTime == 0) + { + return name; + } + else + { + if(System.currentTimeMillis() - lastClickTime < 1000) + { + return name + " **OK**"; + } + else + { + lastClickTime = 0; + return name; + } + } + } + + @Override + void onClick() + { + sendSettingsToRam(); + octoquad.saveParametersToFlash(); + lastClickTime = System.currentTimeMillis(); + } + }; + + optionSendToRAM = new TelemetryMenu.OptionElement() + { + String name = "Send Settings to RAM"; + long lastClickTime = 0; + + @Override + protected String getDisplayText() + { + if(lastClickTime == 0) + { + return name; + } + else + { + if(System.currentTimeMillis() - lastClickTime < 1000) + { + return name + " **OK**"; + } + else + { + lastClickTime = 0; + return name; + } + } + } + + @Override + void onClick() + { + sendSettingsToRam(); + lastClickTime = System.currentTimeMillis(); + } + }; + + rootMenu.addChild(menuHwInfo); + rootMenu.addChild(optionI2cResetMode); + rootMenu.addChild(optionChannelBankConfig); + rootMenu.addChild(menuEncoderDirections); + rootMenu.addChild(menuVelocityIntervals); + rootMenu.addChild(menuAbsParams); + rootMenu.addChild(optionProgramToFlash); + rootMenu.addChild(optionSendToRAM); + rootMenu.addChild(optionExit); + + TelemetryMenu menu = new TelemetryMenu(telemetry, rootMenu); + + while (!isStopRequested()) + { + menu.loop(gamepad1); + telemetry.update(); + sleep(20); + } + } + + void sendSettingsToRam() + { + for(int i = 0; i < OctoQuad.NUM_ENCODERS; i++) + { + octoquad.setSingleEncoderDirection(i, optionsEncoderDirections[i].getValue() ? OctoQuad.EncoderDirection.REVERSE : OctoQuad.EncoderDirection.FORWARD); + octoquad.setSingleVelocitySampleInterval(i, optionsVelocityIntervals[i].getValue()); + + OctoQuad.ChannelPulseWidthParams params = new OctoQuad.ChannelPulseWidthParams(); + params.max_length_us = optionsAbsParamsMax[i].getValue(); + params.min_length_us = optionsAbsParamsMin[i].getValue(); + + octoquad.setSingleChannelPulseWidthParams(i, params); + } + + octoquad.setI2cRecoveryMode((OctoQuad.I2cRecoveryMode) optionI2cResetMode.getValue()); + octoquad.setChannelBankConfig((OctoQuad.ChannelBankConfig) optionChannelBankConfig.getValue()); + } + + /* + * Copyright (c) 2023 OpenFTC Team + * + * 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. + */ + + public static class TelemetryMenu + { + private final MenuElement root; + private MenuElement currentLevel; + + private boolean dpadUpPrev; + private boolean dpadDnPrev; + private boolean dpadRightPrev; + private boolean dpadLeftPrev; + private boolean xPrev; + private boolean lbPrev; + + private int selectedIdx = 0; + private Stack selectedIdxStack = new Stack<>(); + + private final Telemetry telemetry; + + /** + * TelemetryMenu constructor + * @param telemetry pass in 'telemetry' from your OpMode + * @param root the root menu element + */ + public TelemetryMenu(Telemetry telemetry, MenuElement root) + { + this.root = root; + this.currentLevel = root; + this.telemetry = telemetry; + + telemetry.setDisplayFormat(Telemetry.DisplayFormat.HTML); + telemetry.setMsTransmissionInterval(50); + } + + /** + * Call this from inside your loop to put the current menu state into + * telemetry, and process gamepad inputs for navigating the menu + * @param gamepad the gamepad you want to use to navigate the menu + */ + public void loop(Gamepad gamepad) + { + // Capture current state of the gamepad buttons we care about; + // We can only look once or we risk a race condition + boolean dpadUp = gamepad.dpad_up; + boolean dpadDn = gamepad.dpad_down; + boolean dpadRight = gamepad.dpad_right; + boolean dpadLeft = gamepad.dpad_left; + boolean x = gamepad.x; + boolean lb = gamepad.left_bumper; + + // Figure out who our children our at this level + // and figure out which item is currently highlighted + // with the selection pointer + ArrayList children = currentLevel.children(); + Element currentSelection = children.get(selectedIdx); + + // Left and right are inputs to the selected item (if it's an Option) + if (currentSelection instanceof OptionElement) + { + if (dpadRight && !dpadRightPrev) // rising edge + { + ((OptionElement) currentSelection).onRightInput(); + } + else if (dpadLeft && !dpadLeftPrev) // rising edge + { + ((OptionElement) currentSelection).onLeftInput(); + } + } + + // Up and down navigate the current selection pointer + if (dpadUp && !dpadUpPrev) // rising edge + { + selectedIdx--; // Move selection pointer up + } + else if (dpadDn && !dpadDnPrev) // rising edge + { + selectedIdx++; // Move selection pointer down + } + + // Make selected index sane (don't let it go out of bounds) :eyes: + if (selectedIdx >= children.size()) + { + selectedIdx = children.size()-1; + } + else if (selectedIdx < 0) + { + selectedIdx = 0; + } + + // Select: either enter submenu or input to option + else if (x && !xPrev) // rising edge + { + // Select up element + if (currentSelection instanceof SpecialUpElement) + { + // We can only go up if we're not at the root level + if (currentLevel != root) + { + // Restore selection pointer to where it was before + selectedIdx = selectedIdxStack.pop(); + + // Change to the parent level + currentLevel = currentLevel.parent(); + } + } + // Input to option + else if (currentSelection instanceof OptionElement) + { + ((OptionElement) currentSelection).onClick(); + } + // Enter submenu + else if (currentSelection instanceof MenuElement) + { + // Save our current selection pointer so we can restore it + // later if the user navigates back up a level + selectedIdxStack.push(selectedIdx); + + // We have no idea what's in the submenu :monkey: so best to + // just set the selection pointer to the first element + selectedIdx = 0; + + // Now the current level becomes the submenu that the selection + // pointer was on + currentLevel = (MenuElement) currentSelection; + } + } + + // Go up a level + else if (lb && !lbPrev) + { + // We can only go up if we're not at the root level + if (currentLevel != root) + { + // Restore selection pointer to where it was before + selectedIdx = selectedIdxStack.pop(); + + // Change to the parent level + currentLevel = currentLevel.parent(); + } + } + + // Save the current button states so that we can look for + // the rising edge the next time around the loop :) + dpadUpPrev = dpadUp; + dpadDnPrev = dpadDn; + dpadRightPrev = dpadRight; + dpadLeftPrev = dpadLeft; + xPrev = x; + lbPrev = lb; + + // Start building the text display. + // First, we add the static directions for gamepad operation + StringBuilder builder = new StringBuilder(); + builder.append(""); + builder.append("Navigate items.....dpad up/down\n") + .append("Select.............X or Square\n") + .append("Edit option........dpad left/right\n") + .append("Up one level.......left bumper\n"); + builder.append(""); + builder.append("\n"); + + // Now actually add the menu options. We start by adding the name of the current menu level. + builder.append(""); + builder.append("Current Menu: ").append(currentLevel.name).append("\n"); + + // Now we loop through all the child elements of this level and add them + for (int i = 0; i < children.size(); i++) + { + // If the selection pointer is at this index, put a green dot in the box :) + if (selectedIdx == i) + { + builder.append("[] "); + } + // Otherwise, just put an empty box + else + { + builder.append("[ ] "); + } + + // Figure out who the selection pointer is pointing at :eyes: + Element e = children.get(i); + + // If it's pointing at a submenu, indicate that it's a submenu to the user + // by prefixing "> " to the name. + if (e instanceof MenuElement) + { + builder.append("> "); + } + + // Finally, add the element's name + builder.append(e.getDisplayText()); + + // We musn't forget the newline + builder.append("\n"); + } + + // Don't forget to close the font tag either + builder.append(""); + + // Build the string!!!! :nerd: + String menu = builder.toString(); + + // Add it to telemetry + telemetry.addLine(menu); + } + + public static class MenuElement extends Element + { + private String name; + private ArrayList children = new ArrayList<>(); + + /** + * Create a new MenuElement; may either be the root menu, or a submenu (set isRoot accordingly) + * @param name the name for this menu + * @param isRoot whether this is a root menu, or a submenu + */ + public MenuElement(String name, boolean isRoot) + { + this.name = name; + + // If it's not the root menu, we add the up one level option as the first element + if (!isRoot) + { + children.add(new SpecialUpElement()); + } + } + + /** + * Add a child element to this menu (may either be an Option or another menu) + * @param child the child element to add + */ + public void addChild(Element child) + { + child.setParent(this); + children.add(child); + } + + /** + * Add multiple child elements to this menu (may either be option, or another menu) + * @param children the children to add + */ + public void addChildren(Element[] children) + { + for (Element e : children) + { + e.setParent(this); + this.children.add(e); + } + } + + @Override + protected String getDisplayText() + { + return name; + } + + private ArrayList children() + { + return children; + } + } + + public static abstract class OptionElement extends Element + { + /** + * Override this to get notified when the element is clicked + */ + void onClick() {} + + /** + * Override this to get notified when the element gets a "left edit" input + */ + protected void onLeftInput() {} + + /** + * Override this to get notified when the element gets a "right edit" input + */ + protected void onRightInput() {} + } + + public static class EnumOption extends OptionElement + { + protected int idx = 0; + protected Enum[] e; + protected String name; + + public EnumOption(String name, Enum[] e) + { + this.e = e; + this.name = name; + } + + public EnumOption(String name, Enum[] e, Enum def) + { + this(name, e); + idx = def.ordinal(); + } + + @Override + public void onLeftInput() + { + idx++; + + if(idx > e.length-1) + { + idx = 0; + } + } + + @Override + public void onRightInput() + { + idx--; + + if(idx < 0) + { + idx = e.length-1; + } + } + + @Override + public void onClick() + { + //onRightInput(); + } + + @Override + protected String getDisplayText() + { + return String.format("%s: %s", name, e[idx].name()); + } + + public Enum getValue() + { + return e[idx]; + } + } + + public static class IntegerOption extends OptionElement + { + protected int i; + protected int min; + protected int max; + protected String name; + + public IntegerOption(String name, int min, int max, int def) + { + this.name = name; + this.min = min; + this.max = max; + this.i = def; + } + + @Override + public void onLeftInput() + { + i--; + + if(i < min) + { + i = max; + } + } + + @Override + public void onRightInput() + { + i++; + + if(i > max) + { + i = min; + } + } + + @Override + public void onClick() + { + //onRightInput(); + } + + @Override + protected String getDisplayText() + { + return String.format("%s: %d", name, i); + } + + public int getValue() + { + return i; + } + } + + static class BooleanOption extends OptionElement + { + private String name; + private boolean val = true; + + private String customTrue; + private String customFalse; + + BooleanOption(String name, boolean def) + { + this.name = name; + this.val = def; + } + + BooleanOption(String name, boolean def, String customTrue, String customFalse) + { + this(name, def); + this.customTrue = customTrue; + this.customFalse = customFalse; + } + + @Override + public void onLeftInput() + { + val = !val; + } + + @Override + public void onRightInput() + { + val = !val; + } + + @Override + public void onClick() + { + val = !val; + } + + @Override + protected String getDisplayText() + { + String valStr; + + if(customTrue != null && customFalse != null) + { + valStr = val ? customTrue : customFalse; + } + else + { + valStr = val ? "true" : "false"; + } + + return String.format("%s: %s", name, valStr); + } + + public boolean getValue() + { + return val; + } + } + + /** + * + */ + public static class StaticItem extends OptionElement + { + private String name; + + public StaticItem(String name) + { + this.name = name; + } + + @Override + protected String getDisplayText() + { + return name; + } + } + + public static abstract class StaticClickableOption extends OptionElement + { + private String name; + + public StaticClickableOption(String name) + { + this.name = name; + } + + abstract void onClick(); + + @Override + protected String getDisplayText() + { + return name; + } + } + + private static abstract class Element + { + private MenuElement parent; + + protected void setParent(MenuElement parent) + { + this.parent = parent; + } + + protected MenuElement parent() + { + return parent; + } + + protected abstract String getDisplayText(); + } + + private static class SpecialUpElement extends Element + { + @Override + protected String getDisplayText() + { + return ".. ↰ Up One Level"; + } + } + } +} diff --git a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/sample_conventions.md b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/sample_conventions.md index 45968ef9..e85e6254 100644 --- a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/sample_conventions.md +++ b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/external/samples/sample_conventions.md @@ -29,6 +29,11 @@ Concept: This is a sample OpMode that illustrates performing a specific function Each OpMode should try to only demonstrate a single concept so they are easy to locate based on their name. These OpModes may not produce a drivable robot. +Utility: This sample type is provided as a useful tool, or aide, to perform some specific development task. + It is not expected to be something you would include in your own robot code. + To use the tool, comment out the @Disabled annotation and build the App. + Read the comments found in the sample for an explanation of its intended use. + After the prefix, other conventions will apply: * Sensor class names should constructed as: Sensor - Company - Type diff --git a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/internal/FtcOpModeRegister.java b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/internal/FtcOpModeRegister.java index 8c6ea59d..ceab67db 100644 --- a/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/internal/FtcOpModeRegister.java +++ b/FtcRobotController/src/main/java/org/firstinspires/ftc/robotcontroller/internal/FtcOpModeRegister.java @@ -34,8 +34,6 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE import com.qualcomm.robotcore.eventloop.opmode.OpModeManager; import com.qualcomm.robotcore.eventloop.opmode.OpModeRegister; -import org.firstinspires.ftc.robotcontroller.external.samples.ConceptNullOp; - /** * {@link FtcOpModeRegister} is responsible for registering OpModes for use in an FTC game. * @see #register(OpModeManager) @@ -49,7 +47,7 @@ public class FtcOpModeRegister implements OpModeRegister { * There are two mechanisms by which an OpMode may be registered. * * 1) The preferred method is by means of class annotations in the OpMode itself. - * See, for example the class annotations in {@link ConceptNullOp}. + * See, for example the class annotations in {@link org.firstinspires.ftc.robotcontroller.external.samples.ConceptNullOp}. * * 2) The other, retired, method is to modify this {@link #register(OpModeManager)} * method to include explicit calls to OpModeManager.register(). diff --git a/README.md b/README.md index 9b7c9bfa..f7a02c95 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ ## NOTICE -This repository contains the public FTC SDK for the CENTERSTAGE (2023-2024) competition season. +This repository contains the public FTC SDK for the INTO THE DEEP (2024-2025) competition season. ## Welcome! This GitHub repository contains the source code that is used to build an Android app to control a *FIRST* Tech Challenge competition robot. To use this SDK, download/clone the entire project to your local computer. @@ -59,6 +59,135 @@ The readme.md file located in the [/TeamCode/src/main/java/org/firstinspires/ftc # Release Information +## Version 10.1 (20240919-122750) + +### Enhancements +* Adds new OpenCV-based `VisionProcessor`s (which may be attached to a VisionPortal in either Java or Blocks) to help teams implement color processing via computer vision in the INTO THE DEEP game + * `ColorBlobLocatorProcessor` implements OpenCV color "blob" detection. A new sample program `ConceptVisionColorLocator` demonstrates its use. + * A choice is offered between pre-defined color ranges, or creating a custom one in RGB, HSV, or YCrCb color space + * The ability is provided to restrict detection to a specified Region of Interest on the screen + * Functions for applying erosion / dilation morphing to the threshold mask are provided + * Functions for sorting and filtering the returned data are provided + * `PredominantColorProcessor` allows using a region of the camera as a "long range color sensor" to determine the predominant color of that region. A new sample program `ConceptVisionColorSensor` demonstrates its use. + * The determined predominant color is selected from a discrete set of color "swatches", similar to the MINDSTORMS NXT color sensor + * Documentation on this Color Processing feature can be found here: https://ftc-docs.firstinspires.org/color-processing +* Added Blocks sample programs for color sensors: RobotAutoDriveToLine and SensorColor. +* Updated Self-Inspect to identify mismatched RC/DS software versions as a "caution" rather than a "failure." + +### Bug Fixes +* Fixes [AngularVelocity conversion regression](https://github.com/FIRST-Tech-Challenge/FtcRobotController/issues/1070) + +## Version 10.0 (20240828-111152) + +### Breaking Changes +* Java classes and Blocks for TensorFlow Object Detection have been removed. +* `AngularVelocity.unit` which was of type `AngleUnit` has been renamed `AngularVelocity.angleUnit` of type `UnnormalizedAngleUnit` + +### Enhancements +* Sample for REV Digital Indicator has been added - ConceptRevLED +* Adds support for the [Sparkfun QWIIC LED Stick](https://www.sparkfun.com/products/18354) + * To connect it directly, you need this [cable](https://www.sparkfun.com/products/25596) +* Adds ConceptLEDStick OpMode +* Adds Blocks for colors black, blue, cyan, dkgray, gray, green, ltgray, magenta, red, white, and yellow. +* Adds an "evaluate but ignore result" Block that executes the connected block and ignores the result. Allows you to call a function and ignore the return value. +* Adds I2C driver for Maxbotix Maxsonar I2CXL sonar rangefinder +* Adds Blocks for setPwmEnable, setPwmDisable, and isPwmEnabled for servos and CR servos. +* In the Blocks editor: a \n in the ExportToBlocks annotation's comment field is displayed as a line break. +* Telemetry has new method setNumDecimalPlaces +* Telemetry now formats doubles and floats (not inside objects, just by themselves) +* Adds support for the Limelight 3A. +* Adds initial support for the REV Servo Hub + * Both the Robot Controller and Driver Station need to be updated to version 10.0 in order for Servo Hubs to be + configurable as Servo Hubs. If the app on either device is outdated, the Servo Hub will show up as an Expansion Hub, + and some functionality will not work as expected. You should wait to create a configuration that includes a Servo Hub + until both the Driver Station and Robot Controller apps have been updated to version 10.0. + * Updating the Servo Hub's firmware and changing its address can only be done using the REV Hardware Client at this time +* Adds support for the REV 9-Axis IMU (REV-31-3332) + * The REV 9-Axis IMU is only supported by the [Universal IMU interface](https://ftc-docs.firstinspires.org/en/latest/programming_resources/imu/imu.html) + * Adds `Rev9AxisImuOrientationOnRobot` Java class. + * If you mentally substitute this IMU's I2C port for the Control Hub's USB ports, `RevHubOrientationOnRobot` is also compatible with this sensor + * Adds Blocks for Rev9AxisImuOrientationOnRobot, including RevHubImuOrientationOnRobot.xyzOrientation and RevHubImuOrientationOnRobot.zyxOrientation. + * Adds Blocks samples SensorRev9AxisIMUOrthogonal and SensorRev9AxisIMUNonOrthogonal. +* Improves Blocks support for RevHubImuOrientationOnRobot. + * Adds Blocks for RevHubImuOrientationOnRobot.xyzOrientation and RevHubImuOrientationOnRobot.zyxOrientation. + * Adds Blocks samples SensorHubIMUOrthogonal (replaces SensorIMU) and SensorHubIMUNonOrthogonal. +* Updates EasyOpenCV, AprilTag, OpenCV, and `libjpeg-turbo` versions +* Adds Blocks for max and min that take two numbers. +* Adds Blocks OpModes ConceptRevSPARKMini, RobotAutoDriveByEncoder, RobotAutoDriveByGyro, RobotAutoDriveByTime, RobotAutoDriveToAprilTagOmni, and RobotAutoDriveToAprilTagTank. +* Two OpModes with the same name now automatically get renamed with the name followed by a "-" and the class name allowing them to both be on the device. +* Shows the name of the active configuration on the Manage page of the Robot Controller Console +* Updated AprilTag Library for INTO THE DEEP. Notably, `getCurrentGameTagLibrary()` now returns INTO THE DEEP tags. +* Adds Blocks for Telemetry.setMsTransmissionInterval and Telemetry.getMsTransmissionInterval. +* Adds Blocks sample SensorOctoQuad. + +### Bug Fixes +* Fixes a bug where the RevBlinkinLedDriver Blocks were under Actuators in the Blocks editor toolbox. They are now Other Devices. +* Fixes a bug where `Exception`s thrown in user code after a stop was requested by the Driver Station would be silently eaten +* Fixed a bug where if you asked for `AngularVelocity` in a unit different than the device reported it in, it would normalize it between -PI and PI for radians, and -180 and 180 for degrees. + +## Version 9.2 (20240701-085519) + +### Important Notes +* Java classes and Blocks for TensorFlow Object Detection have been deprecated and will be removed in Version 10.0. +* The samples that use TensorFlow Object Detection have been removed. + +### Enhancements +* Adds explanatory text to failed items on the inspection activities. To view the explanatory text tap the red warning icon for a failed item. +* In the Blocks editor: added a new kind of variable set block that sets the variable and also returns the new value. +* Changes the way that camera controls behave for a SwitchableCamera. Now, each method (such as getExposure, getMinExposure, getMaxExposure, setExposure for ExposureControl) acts on the currently active camera. +* Adds support for the REV USB PS4 Compatible Gamepad (REV-31-2983) +* Adds ConceptAprilTagMultiPortal OpMode +* Adds support for OctoQuad Quadrature Encoder & Pulse Width Interface Module +* Adds the ExportAprilTagLibraryToBlocks annotation that indicates that a static method that returns an AprilTagLibrary is exported to the Blocks programming environment. The corresponding block will appear in the Blocks toolbox along with the built-in tag libraries. +* Adds Blocks OpMode ConceptAprilTagOptimizeExposure. +* Adds support for the SparkFun Optical Tracking Odometry sensor. + +### Bug Fixes +* Fixes https://github.com/FIRST-Tech-Challenge/FtcRobotController/issues/942 where visionPortal.close() can cause an IndexOutOfBoundsError. +* Fixes a bug in the blocks editor where collapsed function blocks show a warning "Collapsed blocks contain warnings." when the Blocks OpMode is reopened. +* Fixes a bug where the blocks editor wouldn't warn you that you have unsaved changes when you try to leave. This bug was introduced due to a behavior change in Chrome 119. +* [Issue #764](https://github.com/FIRST-Tech-Challenge/FtcRobotController/issues/764) - Get gain control returns a null pointer for a switchable camera +* Fixes a bug where the correct deadzone for certain gamepads was not applied when Advanced Gamepad Features was enabled + +## Version 9.1 (20240215-115542) + +### Enhancements +* Fixes a problem with Blocks: if the user closes a Block's warning balloon, it will still be closed next time the project is opened in the Blocks editor. +* In the Blocks editor, an alert concerning missing hardware devices is not shown if all the Blocks that use the missing hardware devices are disabled. +* Adds Blocks to support comparing property values CRServo.Direction, DCMotor.Direction, DCMotor.Mode, DCMotor.ZeroPowerBehavior, DigitalChannel.Mode, GyroSensor.HeadingMode, IrSeekerSensor.Mode, and Servo.Direction, to the corresponding enum Block. +* Improves OnBotJava auto-import to correctly import classes when used in certain situations. +* Improves OnBotJava autocomplete to provide better completion options in most cases. + * This fixes an issue where autocomplete would fail if a method with two or more formal parameters was defined. +* In OnBotJava, code folding support was added to expand and collapse code sections +* In OnBotJava, the copyright header is now automatically collapsed loading new files +* For all Blocks OpMode samples, intro comments have been moved to the RunOpMode comment balloon. +* The Clean up Blocks command in the Blocks editor now positions function Blocks so their comment balloons don't overlap other function Blocks. +* Added Blocks OpMode sample SensorTouch. +* Added Java OpMode sample SensorDigitalTouch. +* Several improvements to VisionPortal + * Adds option to control whether the stream is automatically started following a `.build()` call on a VisionPortal Builder + * Adds option to control whether the vision processing statistics overlay is rendered or not + * VisionPortals now implement the `CameraStreamSource` interface, allowing multiportal users to select which portal is routed to the DS in INIT by calling CameraStreamServer.getInstance().setSource(visionPortal). Can be selected via gamepad, between Camera Stream sessions. + * Add option to `AprilTagProcessor` to suppress calibration warnings + * Improves camera calibration warnings + * If a calibration is scaled, the resolution it was scaled from will be listed + * If calibrations exist with the wrong aspect ratio, the calibrated resolutions will be listed + * Fixes race condition which caused app crash when calling `stopStreaming()` immediately followed by `close()` on a VisionPortal + * Fixes IllegalStateException when calling `stopStreaming()` immediately after building a VisionPortal + * Added FTC Blocks counterparts to new Java methods: + * VisionPortal.Builder.setAutoStartStreamOnBuild + * VisionPortal.Builder.setShowStatsOverlay + * AprilTagProcessor.Builder.setSuppressCalibrationWarnings + * CameraStreamServer.setSource​ + +### Bug Fixes +* Fixes a problem where OnBotJava does not apply font size settings to the editor. +* Updates EasyOpenCV dependency to v1.7.1 + * Fixes inability to use EasyOpenCV CameraFactory in OnBotJava + * Fixes entire RC app crash when user pipeline throws an exception + * Fixes entire RC app crash when user user canvas annotator throws an exception + * Use the modern stacktrace display when handling user exceptions instead of the legacy ESTOP telemetry message + ## Version 9.0.1 (20230929-083754) ### Enhancements @@ -358,7 +487,7 @@ This is a bug fix only release to address the following four issues. * Fixes [issue #260](https://github.com/FIRST-Tech-Challenge/FtcRobotController/issues/260) Blocks can't call java method that has a VuforiaLocalizer parameter. * Blocks now has a block labeled VuforiaFreightFrenzy.getVuforiaLocalizer for this. * Added a page to manage the TensorFlow Lite models in /sdcard/FIRST/tflitemodels. To get to the TFLite Models page: - * You can click on the link at the bottom of the the Manage page. + * You can click on the link at the bottom of the Manage page. * You can click on the link at the upper-right the Blocks project page. * Fixes logspam when `isBusy()` is called on a motor not in RTP mode. * Hides the "RC Password" item on the inspection screen for phone-based Robot Controllers. (It is only applicable for Control Hubs). @@ -1043,7 +1172,7 @@ Known issues: This version of the software provides support for the REV Robotics Expansion Hub. This version also includes improvements in the USB communication layer in an effort to enhance system resiliency. If you were using a 2.x version of the software previously, updating to version 3.1 requires that you also update your Driver Station software in addition to updating the Robot Controller software. -Also note that in version 3.10 software, the setMaxSpeed and getMaxSpeed methods are no longer available (not deprecated, they have been removed from the SDK). Also note that the the new 3.x software incorporates motor profiles that a user can select as he/she configures the robot. +Also note that in version 3.10 software, the setMaxSpeed and getMaxSpeed methods are no longer available (not deprecated, they have been removed from the SDK). Also note that the new 3.x software incorporates motor profiles that a user can select as he/she configures the robot. Changes include: * Blocks changes diff --git a/TeamCode/src/main/java/org/firstinspires/ftc/teamcode/drive/LukeSpecifically.java b/TeamCode/src/main/java/org/firstinspires/ftc/teamcode/drive/LukeSpecifically.java new file mode 100644 index 00000000..882db95b --- /dev/null +++ b/TeamCode/src/main/java/org/firstinspires/ftc/teamcode/drive/LukeSpecifically.java @@ -0,0 +1,32 @@ +package org.firstinspires.ftc.teamcode.drive; + +import com.qualcomm.robotcore.eventloop.opmode.LinearOpMode; +import com.qualcomm.robotcore.hardware.DcMotor; + +public class LukeSpecifically extends LinearOpMode { + + + private DcMotor front_left; + private DcMotor front_right; + private DcMotor back_left; + private DcMotor back_right; + + + + @Override + public void runOpMode() throws InterruptedException{ + //the code doesn't wait for start + front_left = hardwareMap.get(DcMotor.class,"left_front_left_dw"); + front_right = hardwareMap.get(DcMotor.class,"right_front"); + back_left = hardwareMap.get(DcMotor.class,"left_back"); + back_right = hardwareMap.get(DcMotor.class,"right_back_right_dw"); + if(gamepad1.left_stick_y > 0){ + front_left.setPower (1); + front_right.setPower((1)); + back_left.setPower(1); + back_right.setPower(1); + + } + + } +} diff --git a/TeamCode/src/main/java/org/firstinspires/ftc/teamcode/opmode/ActualGavinTestTeleOp.java b/TeamCode/src/main/java/org/firstinspires/ftc/teamcode/opmode/ActualGavinTestTeleOp.java new file mode 100644 index 00000000..b6dd9ab5 --- /dev/null +++ b/TeamCode/src/main/java/org/firstinspires/ftc/teamcode/opmode/ActualGavinTestTeleOp.java @@ -0,0 +1,70 @@ +package org.firstinspires.ftc.teamcode.opmode; + +import static org.firstinspires.ftc.robotcore.external.BlocksOpModeCompanion.gamepad1; +import static org.firstinspires.ftc.robotcore.external.BlocksOpModeCompanion.hardwareMap; +import static org.firstinspires.ftc.robotcore.external.BlocksOpModeCompanion.linearOpMode; + +import com.qualcomm.robotcore.eventloop.opmode.LinearOpMode; +import com.qualcomm.robotcore.eventloop.opmode.OpMode; +import com.qualcomm.robotcore.eventloop.opmode.TeleOp; +import com.qualcomm.robotcore.hardware.DcMotor; + +@TeleOp +public class ActualGavinTestTeleOp extends LinearOpMode { + private DcMotor front_left; + private DcMotor front_right; + private DcMotor back_left; + private DcMotor back_right; + + + public void runOpMode() throws InterruptedException { + + front_left = hardwareMap.get(DcMotor.class, "front_left"); + front_right = hardwareMap.get(DcMotor.class, "front_right"); + back_left = hardwareMap.get(DcMotor.class, "back_left"); + back_right = hardwareMap.get(DcMotor.class, "back_right"); + + waitForStart(); + while(opModeIsActive()) + if (gamepad1.right_stick_x>=.3 && gamepad1.left_stick_y>=.3){ + front_left.setPower(1); + front_right.setPower(0); + back_right.setPower(0); + back_left.setPower(1); + } + else if (gamepad1.right_stick_y>=0.3) { + front_left.setPower(1); + front_right.setPower(-1); + back_right.setPower(-1); + back_left.setPower(1); + + + } else if (gamepad1.right_stick_y<=-0.3) { + front_left.setPower(-1); + front_right.setPower(1); + back_right.setPower(1); + back_left.setPower(-1); + + + } + else if (gamepad1.left_stick_x<=-.3) { + front_left.setPower(1); + front_right.setPower(1); + back_left.setPower(1); + back_right.setPower(1); + } else if (gamepad1.left_stick_x>=.3) { + front_left.setPower(-1); + front_right.setPower(-1); + back_left.setPower(-1); + back_right.setPower(-1); + + } else { + front_right.setPower(0); + front_left.setPower(0); + back_left.setPower(0); + back_right.setPower(0); + } + + + + }} diff --git a/TeamCode/src/main/java/org/firstinspires/ftc/teamcode/opmode/LearningTeleOpfor17334.java b/TeamCode/src/main/java/org/firstinspires/ftc/teamcode/opmode/LearningTeleOpfor17334.java new file mode 100644 index 00000000..b2363229 --- /dev/null +++ b/TeamCode/src/main/java/org/firstinspires/ftc/teamcode/opmode/LearningTeleOpfor17334.java @@ -0,0 +1,42 @@ +package org.firstinspires.ftc.teamcode.opmode; + +import com.acmerobotics.dashboard.config.Config; +import com.qualcomm.robotcore.eventloop.opmode.LinearOpMode; +import com.qualcomm.robotcore.eventloop.opmode.TeleOp; +import com.qualcomm.robotcore.hardware.DcMotor; + +@Config + +@TeleOp +public class LearningTeleOpfor17334 extends LinearOpMode { + private DcMotor leftFrontMotor; + private DcMotor rightFrontMotor; + private DcMotor leftBackMotor; + + @Override + public void runOpMode() throws InterruptedException { + + leftFrontMotor = hardwareMap.get(DcMotor.class, "left_front_left_dw"); + rightFrontMotor = hardwareMap.get(DcMotor.class, "right_front"); + waitForStart(); + while(opModeIsActive()){ + if (gamepad1.right_stick_y>=0.1) { + leftFrontMotor.setPower(1); + rightFrontMotor.setPower(-1); + } else if (gamepad1.right_stick_y<=-0.1) { + leftFrontMotor.setPower(-1); + rightFrontMotor.setPower(1); + } else { + leftFrontMotor.setPower(0); + rightFrontMotor.setPower(0); + + } + + + } + + + + + } +} diff --git a/TeamCode/src/main/java/org/firstinspires/ftc/teamcode/opmode/TrumanLearnsTeleOP.java b/TeamCode/src/main/java/org/firstinspires/ftc/teamcode/opmode/TrumanLearnsTeleOP.java new file mode 100644 index 00000000..02e8e84c --- /dev/null +++ b/TeamCode/src/main/java/org/firstinspires/ftc/teamcode/opmode/TrumanLearnsTeleOP.java @@ -0,0 +1,89 @@ +package org.firstinspires.ftc.teamcode.opmode; + + +import com.qualcomm.robotcore.eventloop.opmode.LinearOpMode; +import com.qualcomm.robotcore.eventloop.opmode.TeleOp; +import com.qualcomm.robotcore.hardware.CRServo; +import com.qualcomm.robotcore.hardware.DcMotor; +import com.qualcomm.robotcore.hardware.DcMotorSimple; + +import org.firstinspires.ftc.teamcode.util.Toggle; + +@TeleOp +public class TrumanLearnsTeleOP extends LinearOpMode { + + private DcMotor topLeftMotor; + private DcMotor topRightMotor; + private DcMotor bottomLeftMotor; + private DcMotor bottomRightMotor; + private CRServo tail; + @Override + public void runOpMode() throws InterruptedException { + Toggle myToggleButton = new Toggle(); + double ly; + double lx; + double rx; + double ry; + boolean leftBumper; + boolean rightBumper; //why? just use if statements + topLeftMotor = hardwareMap.get(DcMotor.class,"FL"); + topRightMotor = hardwareMap.get(DcMotor.class,"FR"); + bottomLeftMotor = hardwareMap.get(DcMotor.class,"BL"); + bottomRightMotor = hardwareMap.get(DcMotor.class,"BR"); + topLeftMotor.setDirection(DcMotorSimple.Direction.REVERSE); + bottomLeftMotor.setDirection(DcMotorSimple.Direction.REVERSE); + //tail = hardwareMap.get(CRServo.class,"servo"); ONLY FOR DOG + //double tailAngle = 1; + double motorSpeed = 0.3; //^^ + waitForStart(); + + while (opModeIsActive()){ + + myToggleButton.update(gamepad1.a); + + if (myToggleButton.state){ + lx=gamepad1.right_stick_y; + ly=gamepad1.right_stick_y; + rx=gamepad1.left_stick_y; + ry=gamepad1.left_stick_y; + leftBumper=gamepad1.left_bumper; + rightBumper=gamepad1.right_bumper; + if (leftBumper) { + ly=-1; + lx=1; + } + if (rightBumper) { + rx=1; + ry=-1; + + } + topLeftMotor.setPower(ly); + bottomLeftMotor.setPower(lx); + topRightMotor.setPower(rx); + bottomRightMotor.setPower(ry); + telemetry.addData("Ly", ly); + telemetry.addData("Lx", lx); + telemetry.addData("Rx", rx); + telemetry.addData("Ry", ry); + telemetry.update(); + } + else{ + double y = -gamepad1.left_stick_y; // Remember, Y stick is reversed! + double x = gamepad1.left_stick_x; + double rx2 = gamepad1.right_stick_x; + + topLeftMotor.setPower(y+ x + rx2); + bottomLeftMotor.setPower(y - x + rx2); + topRightMotor.setPower(y - x - rx2); + bottomRightMotor.setPower(y + x - rx2); + } + + //while(!check){ + //put the other stuff that isn't t-bar steering here + } + } +} + + + + diff --git a/TeamCode/src/main/java/org/firstinspires/ftc/teamcode/vision/PropellerDetection1.java b/TeamCode/src/main/java/org/firstinspires/ftc/teamcode/vision/PropellerDetection1.java deleted file mode 100644 index 1f0efc13..00000000 --- a/TeamCode/src/main/java/org/firstinspires/ftc/teamcode/vision/PropellerDetection1.java +++ /dev/null @@ -1,194 +0,0 @@ -/* Copyright (c) 2019 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.vision; - -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.BuiltinCameraDirection; -import org.firstinspires.ftc.robotcore.external.hardware.camera.WebcamName; -import org.firstinspires.ftc.robotcore.external.tfod.Recognition; -import org.firstinspires.ftc.vision.VisionPortal; -import org.firstinspires.ftc.vision.tfod.TfodProcessor; - -import java.util.List; - -/* - * This OpMode illustrates the basics of TensorFlow Object Detection, - * including Java Builder structures for specifying Vision 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. - */ -@TeleOp(name = "propeller", group = "Concept") -@Disabled -public class PropellerDetection1 extends LinearOpMode { - - private static final boolean USE_WEBCAM = true; // true for webcam, false for phone camera - - /** - * The variable to store our instance of the TensorFlow Object Detection processor. - */ - private TfodProcessor tfod; - - /** - * The variable to store our instance of the vision portal. - */ - private VisionPortal visionPortal; - - @Override - public void runOpMode() { - - initTfod(); - - // Wait for the DS start button to be touched. - telemetry.addData("DS preview on/off", "3 dots, Camera Stream"); - telemetry.addData(">", "Touch Play to start OpMode"); - telemetry.update(); - waitForStart(); - - if (opModeIsActive()) { - while (opModeIsActive()) { - - telemetryTfod(); - - // Push telemetry to the Driver Station. - telemetry.update(); - - // Save CPU resources; can resume streaming when needed. - if (gamepad1.dpad_down) { - visionPortal.stopStreaming(); - } else if (gamepad1.dpad_up) { - visionPortal.resumeStreaming(); - } - - // Share the CPU. - sleep(20); - } - } - - // Save more CPU resources when camera is no longer needed. - visionPortal.close(); - - } // end runOpMode() - - //private static String TFOD_MODEL_ASSET = "model_20231106_171216.tflite"; - //private static String TFOD_MODEL_ASSET = "model_20231116_151933.tflite"; - //private static String TFOD_MODEL_ASSET = "model_20231121_104059.tflite"; - //private static String TFOD_MODEL_ASSET = "model_20231127_143238.tflite"; - private static final String TFOD_MODEL_ASSET = "model_20231207_153054.tflite"; - private static final String[] LABELS = { - "prop", - }; - /** - * Initialize the TensorFlow Object Detection processor. - */ - private void initTfod() { - - // Create the TensorFlow processor by using a builder. - tfod = new TfodProcessor.Builder() - // .setModelAssetName("model_20231104_124524.tflite") - - // Use setModelAssetName() if the TF Model is built in as an asset. - // Use setModelFileName() if you have downloaded a custom team model to the Robot Controller. - .setModelAssetName(TFOD_MODEL_ASSET) - //.setModelFileName(TFOD_MODEL_FILE) - - .setModelLabels(LABELS) - //.setIsModelTensorFlow2(true) - //.setIsModelQuantized(true) - //.setModelInputSize(300) - //.setModelAspectRatio(16.0 / 9.0) - - .build(); - - // Create the vision portal by using a builder. - VisionPortal.Builder builder = new VisionPortal.Builder(); - - // Set the camera (webcam vs. built-in RC phone camera). - if (USE_WEBCAM) { - builder.setCamera(hardwareMap.get(WebcamName.class, "Center")); - } else { - builder.setCamera(BuiltinCameraDirection.BACK); - } - - // Choose a camera resolution. Not all cameras support all resolutions. - builder.setCameraResolution(new Size(640, 480)); - - // Enable the RC preview (LiveView). Set "false" to omit camera monitoring. - //builder.enableCameraMonitoring(true); - - // Set the stream format; MJPEG uses less bandwidth than default YUY2. - //builder.setStreamFormat(VisionPortal.StreamFormat.YUY2); - - // Choose whether or not LiveView stops if no processors are enabled. - // If set "true", monitor shows solid orange screen if no processors enabled. - // If set "false", monitor shows camera view without annotations. - //builder.setAutoStopLiveView(false); - - // Set and enable the processor. - builder.addProcessor(tfod); - - // Build the Vision Portal, using the above settings. - visionPortal = builder.build(); - - // Set confidence threshold for TFOD recognitions, at any time. - //tfod.setMinResultConfidence(0.75f); - - // Disable or re-enable the TFOD processor at any time. - //visionPortal.setProcessorEnabled(tfod, true); - - } // end method initTfod() - - /** - * Add telemetry about TensorFlow Object Detection (TFOD) recognitions. - */ - private void telemetryTfod() { - - List currentRecognitions = tfod.getRecognitions(); - telemetry.addData("# Objects Detected", currentRecognitions.size()); - - // Step through the list of recognitions and display info for each one. - for (Recognition recognition : currentRecognitions) { - double x = (recognition.getLeft() + recognition.getRight()) / 2 ; - double y = (recognition.getTop() + recognition.getBottom()) / 2 ; - - telemetry.addData(""," "); - telemetry.addData("Image", "%s (%.0f %% Conf.)", recognition.getLabel(), recognition.getConfidence() * 100); - telemetry.addData("- Position", "%.0f / %.0f", x, y); - telemetry.addData("- Size", "%.0f x %.0f", recognition.getWidth(), recognition.getHeight()); - } // end for() loop - - } // end method telemetryTfod() - -} // end class diff --git a/TeamCode/src/main/java/org/firstinspires/ftc/teamcode/vision/PropellerDetection2.java b/TeamCode/src/main/java/org/firstinspires/ftc/teamcode/vision/PropellerDetection2.java deleted file mode 100644 index d8af267a..00000000 --- a/TeamCode/src/main/java/org/firstinspires/ftc/teamcode/vision/PropellerDetection2.java +++ /dev/null @@ -1,197 +0,0 @@ -/* Copyright (c) 2019 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.vision; - -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.BuiltinCameraDirection; -import org.firstinspires.ftc.robotcore.external.hardware.camera.WebcamName; -import org.firstinspires.ftc.robotcore.external.tfod.Recognition; -import org.firstinspires.ftc.teamcode.util.GlobalOpMode; -import org.firstinspires.ftc.vision.VisionPortal; -import org.firstinspires.ftc.vision.tfod.TfodProcessor; - -import java.util.List; - -/* - * This OpMode illustrates the basics of TensorFlow Object Detection, - * including Java Builder structures for specifying Vision 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. - */ -@TeleOp(name = "betterPropeller", group = "Concept") -@Disabled -public class PropellerDetection2 extends LinearOpMode { - - private static final boolean USE_WEBCAM = true; // true for webcam, false for phone camera - - /** - * The variable to store our instance of the TensorFlow Object Detection processor. - */ - private TfodProcessor tfod; - - /** - * The variable to store our instance of the vision portal. - */ - private VisionPortal visionPortal; - - @Override - public void runOpMode() { - GlobalOpMode.opMode = this; - - TensorFlowDetection tfod = new TensorFlowDetection(hardwareMap.get(WebcamName.class, "Center")); - //initTfod(); - - // Wait for the DS start button to be touched. - telemetry.addData("DS preview on/off", "3 dots, Camera Stream"); - telemetry.addData(">", "Touch Play to start OpMode"); - telemetry.update(); - //waitForStart(); - - if (opModeIsActive() || opModeInInit()) { - while (opModeIsActive() || opModeInInit()) { - //tfod.getPropPosition(); -// telemetryTfod(); -// -// // Push telemetry to the Driver Station. -// telemetry.update(); -// -// // Save CPU resources; can resume streaming when needed. -// if (gamepad1.dpad_down) { -// visionPortal.stopStreaming(); -// } else if (gamepad1.dpad_up) { -// visionPortal.resumeStreaming(); -// } -// -// // Share the CPU. -// sleep(20); - } - } - - // Save more CPU resources when camera is no longer needed. - visionPortal.close(); - - } // end runOpMode() - - //private static String TFOD_MODEL_ASSET = "model_20231106_171216.tflite"; - //private static String TFOD_MODEL_ASSET = "model_20231116_151933.tflite"; - //private static String TFOD_MODEL_ASSET = "model_20231121_104059.tflite"; - private static final String TFOD_MODEL_ASSET = "model_20231127_143238.tflite"; - //private static String TFOD_MODEL_ASSET = "model_20231207_153054.tflite"; - private static final String[] LABELS = { - "prop", - }; - /** - * Initialize the TensorFlow Object Detection processor. - */ - private void initTfod() { - - // Create the TensorFlow processor by using a builder. - tfod = new TfodProcessor.Builder() - // .setModelAssetName("model_20231104_124524.tflite") - - // Use setModelAssetName() if the TF Model is built in as an asset. - // Use setModelFileName() if you have downloaded a custom team model to the Robot Controller. - .setModelAssetName(TFOD_MODEL_ASSET) - //.setModelFileName(TFOD_MODEL_FILE) - - .setModelLabels(LABELS) - //.setIsModelTensorFlow2(true) - //.setIsModelQuantized(true) - //.setModelInputSize(300) - //.setModelAspectRatio(16.0 / 9.0) - - .build(); - - // Create the vision portal by using a builder. - VisionPortal.Builder builder = new VisionPortal.Builder(); - - // Set the camera (webcam vs. built-in RC phone camera). - if (USE_WEBCAM) { - builder.setCamera(hardwareMap.get(WebcamName.class, "Center")); - } else { - builder.setCamera(BuiltinCameraDirection.BACK); - } - - // Choose a camera resolution. Not all cameras support all resolutions. - builder.setCameraResolution(new Size(640, 480)); - - // Enable the RC preview (LiveView). Set "false" to omit camera monitoring. - //builder.enableCameraMonitoring(true); - - // Set the stream format; MJPEG uses less bandwidth than default YUY2. - //builder.setStreamFormat(VisionPortal.StreamFormat.YUY2); - - // Choose whether or not LiveView stops if no processors are enabled. - // If set "true", monitor shows solid orange screen if no processors enabled. - // If set "false", monitor shows camera view without annotations. - //builder.setAutoStopLiveView(false); - - // Set and enable the processor. - builder.addProcessor(tfod); - - // Build the Vision Portal, using the above settings. - visionPortal = builder.build(); - - // Set confidence threshold for TFOD recognitions, at any time. - //tfod.setMinResultConfidence(0.75f); - - // Disable or re-enable the TFOD processor at any time. - //visionPortal.setProcessorEnabled(tfod, true); - - } // end method initTfod() - - /** - * Add telemetry about TensorFlow Object Detection (TFOD) recognitions. - */ - private void telemetryTfod() { - - List currentRecognitions = tfod.getRecognitions(); - telemetry.addData("# Objects Detected", currentRecognitions.size()); - - // Step through the list of recognitions and display info for each one. - for (Recognition recognition : currentRecognitions) { - double x = (recognition.getLeft() + recognition.getRight()) / 2 ; - double y = (recognition.getTop() + recognition.getBottom()) / 2 ; - - telemetry.addData(""," "); - telemetry.addData("Image", "%s (%.0f %% Conf.)", recognition.getLabel(), recognition.getConfidence() * 100); - telemetry.addData("- Position", "%.0f / %.0f", x, y); - telemetry.addData("- Size", "%.0f x %.0f", recognition.getWidth(), recognition.getHeight()); - } // end for() loop - - } // end method telemetryTfod() - -} // end class diff --git a/TeamCode/src/main/java/org/firstinspires/ftc/teamcode/vision/PropellerDetection3.java b/TeamCode/src/main/java/org/firstinspires/ftc/teamcode/vision/PropellerDetection3.java deleted file mode 100644 index 479f0e0b..00000000 --- a/TeamCode/src/main/java/org/firstinspires/ftc/teamcode/vision/PropellerDetection3.java +++ /dev/null @@ -1,198 +0,0 @@ -/* Copyright (c) 2019 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.vision; - -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.BuiltinCameraDirection; -import org.firstinspires.ftc.robotcore.external.hardware.camera.WebcamName; -import org.firstinspires.ftc.robotcore.external.tfod.Recognition; -import org.firstinspires.ftc.teamcode.util.GlobalOpMode; -import org.firstinspires.ftc.vision.VisionPortal; -import org.firstinspires.ftc.vision.tfod.TfodProcessor; - -import java.util.List; - -/* - * This OpMode illustrates the basics of TensorFlow Object Detection, - * including Java Builder structures for specifying Vision 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. - */ -@TeleOp(name = "betterPropeller2(hope)", group = "Concept") -@Disabled -public class PropellerDetection3 extends LinearOpMode { - - private static final boolean USE_WEBCAM = true; // true for webcam, false for phone camera - - /** - * The variable to store our instance of the TensorFlow Object Detection processor. - */ - private TfodProcessor tfod; - - /** - * The variable to store our instance of the vision portal. - */ - private VisionPortal visionPortal; - - @Override - public void runOpMode() { - GlobalOpMode.opMode = this; - - TensorFlowDetection tfod = new TensorFlowDetection(hardwareMap.get(WebcamName.class, "Center")); - //initTfod(); - - // Wait for the DS start button to be touched. - telemetry.addData("DS preview on/off", "3 dots, Camera Stream"); - telemetry.addData(">", "Touch Play to start OpMode"); - telemetry.update(); - //waitForStart(); - - if (opModeIsActive() || opModeInInit()) { - while (opModeIsActive() || opModeInInit()) { - //tfod.getPropPosition(); -// telemetryTfod(); -// -// // Push telemetry to the Driver Station. -// telemetry.update(); -// -// // Save CPU resources; can resume streaming when needed. -// if (gamepad1.dpad_down) { -// visionPortal.stopStreaming(); -// } else if (gamepad1.dpad_up) { -// visionPortal.resumeStreaming(); -// } -// -// // Share the CPU. -// sleep(20); - } - } - - // Save more CPU resources when camera is no longer needed. - visionPortal.close(); - - } // end runOpMode() - - //private static String TFOD_MODEL_ASSET = "model_20231106_171216.tflite"; - //private static String TFOD_MODEL_ASSET = "model_20231116_151933.tflite"; - //private static String TFOD_MODEL_ASSET = "model_20231121_104059.tflite"; - //private static String TFOD_MODEL_ASSET = "model_20231127_143238.tflite"; - //private static String TFOD_MODEL_ASSET = "model_20231207_153054.tflite"; - private static final String TFOD_MODEL_ASSET = "model_20231209_095349.tflite"; - private static final String[] LABELS = { - "prop", - }; - /** - * Initialize the TensorFlow Object Detection processor. - */ - private void initTfod() { - - // Create the TensorFlow processor by using a builder. - tfod = new TfodProcessor.Builder() - // .setModelAssetName("model_20231104_124524.tflite") - - // Use setModelAssetName() if the TF Model is built in as an asset. - // Use setModelFileName() if you have downloaded a custom team model to the Robot Controller. - .setModelAssetName(TFOD_MODEL_ASSET) - //.setModelFileName(TFOD_MODEL_FILE) - - .setModelLabels(LABELS) - //.setIsModelTensorFlow2(true) - //.setIsModelQuantized(true) - //.setModelInputSize(300) - //.setModelAspectRatio(16.0 / 9.0) - - .build(); - - // Create the vision portal by using a builder. - VisionPortal.Builder builder = new VisionPortal.Builder(); - - // Set the camera (webcam vs. built-in RC phone camera). - if (USE_WEBCAM) { - builder.setCamera(hardwareMap.get(WebcamName.class, "Center")); - } else { - builder.setCamera(BuiltinCameraDirection.BACK); - } - - // Choose a camera resolution. Not all cameras support all resolutions. - builder.setCameraResolution(new Size(640, 480)); - - // Enable the RC preview (LiveView). Set "false" to omit camera monitoring. - //builder.enableCameraMonitoring(true); - - // Set the stream format; MJPEG uses less bandwidth than default YUY2. - //builder.setStreamFormat(VisionPortal.StreamFormat.YUY2); - - // Choose whether or not LiveView stops if no processors are enabled. - // If set "true", monitor shows solid orange screen if no processors enabled. - // If set "false", monitor shows camera view without annotations. - //builder.setAutoStopLiveView(false); - - // Set and enable the processor. - builder.addProcessor(tfod); - - // Build the Vision Portal, using the above settings. - visionPortal = builder.build(); - - // Set confidence threshold for TFOD recognitions, at any time. - //tfod.setMinResultConfidence(0.75f); - - // Disable or re-enable the TFOD processor at any time. - //visionPortal.setProcessorEnabled(tfod, true); - - } // end method initTfod() - - /** - * Add telemetry about TensorFlow Object Detection (TFOD) recognitions. - */ - private void telemetryTfod() { - - List currentRecognitions = tfod.getRecognitions(); - telemetry.addData("# Objects Detected", currentRecognitions.size()); - - // Step through the list of recognitions and display info for each one. - for (Recognition recognition : currentRecognitions) { - double x = (recognition.getLeft() + recognition.getRight()) / 2 ; - double y = (recognition.getTop() + recognition.getBottom()) / 2 ; - - telemetry.addData(""," "); - telemetry.addData("Image", "%s (%.0f %% Conf.)", recognition.getLabel(), recognition.getConfidence() * 100); - telemetry.addData("- Position", "%.0f / %.0f", x, y); - telemetry.addData("- Size", "%.0f x %.0f", recognition.getWidth(), recognition.getHeight()); - } // end for() loop - - } // end method telemetryTfod() - -} // end class diff --git a/TeamCode/src/main/java/org/firstinspires/ftc/teamcode/vision/TensorFlowDetection.java b/TeamCode/src/main/java/org/firstinspires/ftc/teamcode/vision/TensorFlowDetection.java index 08d0425e..6022b19a 100644 --- a/TeamCode/src/main/java/org/firstinspires/ftc/teamcode/vision/TensorFlowDetection.java +++ b/TeamCode/src/main/java/org/firstinspires/ftc/teamcode/vision/TensorFlowDetection.java @@ -3,10 +3,10 @@ import android.util.Size; import org.firstinspires.ftc.robotcore.external.hardware.camera.WebcamName; -import org.firstinspires.ftc.robotcore.external.tfod.Recognition; +//import org.firstinspires.ftc.robotcore.external.tfod.Recognition; import org.firstinspires.ftc.teamcode.util.Timeout; import org.firstinspires.ftc.vision.VisionPortal; -import org.firstinspires.ftc.vision.tfod.TfodProcessor; +//import org.firstinspires.ftc.vision.tfod.TfodProcessor; import java.util.List; @@ -17,16 +17,16 @@ public class TensorFlowDetection { /** * The variable to store our instance of the TensorFlow Object Detection processor. */ - private final TfodProcessor tfod; + //private TfodProcessor tfod; /** * The variable to store our instance of the vision portal. */ - private final VisionPortal visionPortal; + private VisionPortal visionPortal; //private static String TFOD_MODEL_ASSET = "model_20231127_143238.tflite"; //model without negatives //private static String TFOD_MODEL_ASSET = "model_20231209_095349.tflite"; //model with negatives //private static String TFOD_MODEL_ASSET = "model_20240309_150637.tflite"; - private static final String TFOD_MODEL_ASSET = "goodModel.tflite"; + private static String TFOD_MODEL_ASSET = "goodModel.tflite"; private static final String[] LABELS = { "prop", }; @@ -34,21 +34,21 @@ public TensorFlowDetection(WebcamName camera) { // Create the TensorFlow processor by using a builder. - tfod = new TfodProcessor.Builder() - // .setModelAssetName("model_20231104_124524.tflite") - - // Use setModelAssetName() if the TF Model is built in as an asset. - // Use setModelFileName() if you have downloaded a custom team model to the Robot Controller. - .setModelAssetName(TFOD_MODEL_ASSET) - //.setModelFileName(TFOD_MODEL_FILE) - - .setModelLabels(LABELS) - //.setIsModelTensorFlow2(true) - //.setIsModelQuantized(true) - //.setModelInputSize(300) - //.setModelAspectRatio(16.0 / 9.0) - - .build(); +// tfod = new TfodProcessor.Builder() +// // .setModelAssetName("model_20231104_124524.tflite") +// +// // Use setModelAssetName() if the TF Model is built in as an asset. +// // Use setModelFileName() if you have downloaded a custom team model to the Robot Controller. +// .setModelAssetName(TFOD_MODEL_ASSET) +// //.setModelFileName(TFOD_MODEL_FILE) +// +// .setModelLabels(LABELS) +// //.setIsModelTensorFlow2(true) +// //.setIsModelQuantized(true) +// //.setModelInputSize(300) +// //.setModelAspectRatio(16.0 / 9.0) +// +// .build(); // Create the vision portal by using a builder. VisionPortal.Builder builder = new VisionPortal.Builder(); @@ -71,7 +71,7 @@ public TensorFlowDetection(WebcamName camera) { //builder.setAutoStopLiveView(false); // Set and enable the processor. - builder.addProcessor(tfod); + //builder.addProcessor(tfod); // Build the Vision Portal, using the above settings. visionPortal = builder.build(); @@ -109,15 +109,15 @@ public enum PropPosition{ public PropPosition getPropPosition(Timeout timeout) { - List currentRecognitions = tfod.getRecognitions(); - while(currentRecognitions.size() < 1 && !timeout.expired()) { - //android.util.Log.w("TENSORFLOW", "Spinning for current recognitions..."); - currentRecognitions = tfod.getRecognitions(); - } - if (currentRecognitions.size() < 1) { - return null; - } - Recognition recognition = currentRecognitions.get(0); +// List currentRecognitions = tfod.getRecognitions(); +// while(currentRecognitions.size() < 1 && !timeout.expired()) { +// //android.util.Log.w("TENSORFLOW", "Spinning for current recognitions..."); +// currentRecognitions = tfod.getRecognitions(); +// } +// if (currentRecognitions.size() < 1) { +// return null; +// } +// Recognition recognition = currentRecognitions.get(0); // while (recognition.getWidth() > 300 && !GlobalOpMode.opMode.isStopRequested()) { // android.util.Log.w("TENSORFLOW", "Spinning for current recognitions..."); // for (Recognition rec :currentRecognitions) { @@ -132,20 +132,20 @@ public PropPosition getPropPosition(Timeout timeout) { - double centerX = (recognition.getLeft() + recognition.getRight()) / 2 ; - if (centerX < 214) { - //android.util.Log.w("TENSORFLOW", "LEFT"); - return PropPosition.LEFT; - } else if(centerX > 214 && centerX < 428) { - //android.util.Log.w("TENSORFLOW", "CENTER"); - return PropPosition.CENTER; - } else { - //android.util.Log.w("TENSORFLOW", "RIGHT"); - return PropPosition.RIGHT; - } - +// double centerX = (recognition.getLeft() + recognition.getRight()) / 2 ; +// if (centerX < 214) { +// //android.util.Log.w("TENSORFLOW", "LEFT"); +// return PropPosition.LEFT; +// } else if(centerX > 214 && centerX < 428) { +// //android.util.Log.w("TENSORFLOW", "CENTER"); +// return PropPosition.CENTER; +// } else { +// //android.util.Log.w("TENSORFLOW", "RIGHT"); +// return PropPosition.RIGHT; +// } + return null; } } diff --git a/TeamCode/src/main/java/org/firstinspires/ftc/teamcode/vision/WhitePixelDetection.java b/TeamCode/src/main/java/org/firstinspires/ftc/teamcode/vision/WhitePixelDetection.java deleted file mode 100644 index ab04ba71..00000000 --- a/TeamCode/src/main/java/org/firstinspires/ftc/teamcode/vision/WhitePixelDetection.java +++ /dev/null @@ -1,184 +0,0 @@ -/* Copyright (c) 2019 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.vision; - -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.BuiltinCameraDirection; -import org.firstinspires.ftc.robotcore.external.hardware.camera.WebcamName; -import org.firstinspires.ftc.robotcore.external.tfod.Recognition; -import org.firstinspires.ftc.vision.VisionPortal; -import org.firstinspires.ftc.vision.tfod.TfodProcessor; - -import java.util.List; - -/* - * This OpMode illustrates the basics of TensorFlow Object Detection, - * including Java Builder structures for specifying Vision 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. - */ -@TeleOp(name = "Concept: TensorFlow Object Detection", group = "Concept") -@Disabled -public class WhitePixelDetection extends LinearOpMode { - - private static final boolean USE_WEBCAM = true; // true for webcam, false for phone camera - - /** - * The variable to store our instance of the TensorFlow Object Detection processor. - */ - private TfodProcessor tfod; - - /** - * The variable to store our instance of the vision portal. - */ - private VisionPortal visionPortal; - - @Override - public void runOpMode() { - - initTfod(); - - // Wait for the DS start button to be touched. - telemetry.addData("DS preview on/off", "3 dots, Camera Stream"); - telemetry.addData(">", "Touch Play to start OpMode"); - telemetry.update(); - waitForStart(); - - if (opModeIsActive()) { - while (opModeIsActive()) { - - telemetryTfod(); - - // Push telemetry to the Driver Station. - telemetry.update(); - - // Save CPU resources; can resume streaming when needed. - if (gamepad1.dpad_down) { - visionPortal.stopStreaming(); - } else if (gamepad1.dpad_up) { - visionPortal.resumeStreaming(); - } - - // Share the CPU. - sleep(20); - } - } - - // Save more CPU resources when camera is no longer needed. - visionPortal.close(); - - } // end runOpMode() - - /** - * Initialize the TensorFlow Object Detection processor. - */ - private void initTfod() { - - // Create the TensorFlow processor by using a builder. - tfod = new TfodProcessor.Builder() - - - // Use setModelAssetName() if the TF Model is built in as an asset. - // Use setModelFileName() if you have downloaded a custom team model to the Robot Controller. - //.setModelAssetName(TFOD_MODEL_ASSET) - //.setModelFileName(TFOD_MODEL_FILE) - - - //.setIsModelTensorFlow2(true) - //.setIsModelQuantized(true) - //.setModelInputSize(300) - //.setModelAspectRatio(16.0 / 9.0) - - .build(); - - // Create the vision portal by using a builder. - VisionPortal.Builder builder = new VisionPortal.Builder(); - - // Set the camera (webcam vs. built-in RC phone camera). - if (USE_WEBCAM) { - builder.setCamera(hardwareMap.get(WebcamName.class, "Webcam 1")); - } else { - builder.setCamera(BuiltinCameraDirection.BACK); - } - - // Choose a camera resolution. Not all cameras support all resolutions. - //builder.setCameraResolution(new Size(640, 480)); - - // Enable the RC preview (LiveView). Set "false" to omit camera monitoring. - //builder.enableCameraMonitoring(true); - - // Set the stream format; MJPEG uses less bandwidth than default YUY2. - //builder.setStreamFormat(VisionPortal.StreamFormat.YUY2); - - // Choose whether or not LiveView stops if no processors are enabled. - // If set "true", monitor shows solid orange screen if no processors enabled. - // If set "false", monitor shows camera view without annotations. - //builder.setAutoStopLiveView(false); - - // Set and enable the processor. - builder.addProcessor(tfod); - - // Build the Vision Portal, using the above settings. - visionPortal = builder.build(); - - // Set confidence threshold for TFOD recognitions, at any time. - //tfod.setMinResultConfidence(0.75f); - - // Disable or re-enable the TFOD processor at any time. - //visionPortal.setProcessorEnabled(tfod, true); - - } // end method initTfod() - - /** - * Add telemetry about TensorFlow Object Detection (TFOD) recognitions. - */ - private void telemetryTfod() { - - List currentRecognitions = tfod.getRecognitions(); - telemetry.addData("# Objects Detected", currentRecognitions.size()); - - // Step through the list of recognitions and display info for each one. - for (Recognition recognition : currentRecognitions) { - double x = (recognition.getLeft() + recognition.getRight()) / 2 ; - double y = (recognition.getTop() + recognition.getBottom()) / 2 ; - - telemetry.addData(""," "); - telemetry.addData("Image", "%s (%.0f %% Conf.)", recognition.getLabel(), recognition.getConfidence() * 100); - telemetry.addData("- Position", "%.0f / %.0f", x, y); - telemetry.addData("- Size", "%.0f x %.0f", recognition.getWidth(), recognition.getHeight()); - } // end for() loop - - } // end method telemetryTfod() - -} // end class diff --git a/build.common.gradle b/build.common.gradle index a587ce7d..4c776cc0 100644 --- a/build.common.gradle +++ b/build.common.gradle @@ -47,10 +47,6 @@ android { } } - aaptOptions { - noCompress "tflite" - } - defaultConfig { signingConfig signingConfigs.debug applicationId 'com.qualcomm.ftcrobotcontroller' diff --git a/build.dependencies.gradle b/build.dependencies.gradle index 3eda3554..ff4275de 100644 --- a/build.dependencies.gradle +++ b/build.dependencies.gradle @@ -5,18 +5,14 @@ repositories { } dependencies { - implementation 'org.firstinspires.ftc:Inspection:9.0.1' - implementation 'org.firstinspires.ftc:Blocks:9.0.1' - implementation 'org.firstinspires.ftc:Tfod:9.0.1' - implementation 'org.firstinspires.ftc:RobotCore:9.0.1' - implementation 'org.firstinspires.ftc:RobotServer:9.0.1' - implementation 'org.firstinspires.ftc:OnBotJava:9.0.1' - implementation 'org.firstinspires.ftc:Hardware:9.0.1' - implementation 'org.firstinspires.ftc:FtcCommon:9.0.1' - implementation 'org.firstinspires.ftc:Vision:9.0.1' - implementation 'org.firstinspires.ftc:gameAssets-CenterStage:1.0.0' - implementation 'org.tensorflow:tensorflow-lite-task-vision:0.4.3' - runtimeOnly 'org.tensorflow:tensorflow-lite:2.12.0' + implementation 'org.firstinspires.ftc:Inspection:10.1.0' + implementation 'org.firstinspires.ftc:Blocks:10.1.0' + implementation 'org.firstinspires.ftc:RobotCore:10.1.0' + implementation 'org.firstinspires.ftc:RobotServer:10.1.0' + implementation 'org.firstinspires.ftc:OnBotJava:10.1.0' + implementation 'org.firstinspires.ftc:Hardware:10.1.0' + implementation 'org.firstinspires.ftc:FtcCommon:10.1.0' + implementation 'org.firstinspires.ftc:Vision:10.1.0' implementation 'androidx.appcompat:appcompat:1.2.0' implementation 'com.acmerobotics.dashboard:dashboard:0.4.12' } diff --git a/gradle.properties b/gradle.properties index f836e69c..1d70af5a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,8 +3,8 @@ # https://developer.android.com/topic/libraries/support-library/androidx-rn android.useAndroidX=true -# Automatically convert third-party libraries to use AndroidX -android.enableJetifier=true +# We no longer need to auto-convert third-party libraries to use AndroidX, which slowed down the build +android.enableJetifier=false # Enable build caching org.gradle.caching=true