FtcRobotController v12.0

This commit is contained in:
Cal Kestis
2026-09-07 10:03:02 -07:00
parent 26cd1fdd2a
commit 7cf073d87e
9 changed files with 277 additions and 146 deletions
@@ -2,7 +2,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:versionCode="63" android:versionCode="63"
android:versionName="11.2.1"> android:versionName="12.0">
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
@@ -38,8 +38,10 @@ import org.firstinspires.ftc.robotcore.external.hardware.camera.CameraCompatibil
import org.firstinspires.ftc.robotcore.external.hardware.camera.WebcamName; import org.firstinspires.ftc.robotcore.external.hardware.camera.WebcamName;
import org.firstinspires.ftc.robotcore.internal.usb.UsbConstants; import org.firstinspires.ftc.robotcore.internal.usb.UsbConstants;
import org.firstinspires.ftc.vision.VisionPortal; import org.firstinspires.ftc.vision.VisionPortal;
import org.firstinspires.ftc.vision.apriltag.AprilTagClusterDetection;
import org.firstinspires.ftc.vision.apriltag.AprilTagDetection; import org.firstinspires.ftc.vision.apriltag.AprilTagDetection;
import org.firstinspires.ftc.vision.apriltag.AprilTagProcessor; import org.firstinspires.ftc.vision.apriltag.AprilTagProcessor;
import org.firstinspires.ftc.vision.apriltag.AprilTagSingleDetection;
import java.util.List; import java.util.List;
@@ -150,12 +152,12 @@ public class ConceptAprilTag extends LinearOpMode {
aprilTag = new AprilTagProcessor.Builder() aprilTag = new AprilTagProcessor.Builder()
// The following default settings are available to un-comment and edit as needed. // The following default settings are available to un-comment and edit as needed.
//.setDrawAxes(false) //.setDrawAxes(true) // Changed in V12.0
//.setDrawCubeProjection(false)
//.setDrawTagOutline(true) //.setDrawTagOutline(true)
//.setTagFamily(AprilTagProcessor.TagFamily.TAG_36h11) //.setTagFamily(AprilTagProcessor.TagFamily.TAG_36h11)
//.setTagLibrary(AprilTagGameDatabase.getCenterStageTagLibrary()) //.setTagLibrary(AprilTagGameDatabase.getCenterStageTagLibrary())
//.setOutputUnits(DistanceUnit.INCH, AngleUnit.DEGREES) //.setOutputUnits(DistanceUnit.INCH, AngleUnit.DEGREES)
//.setDrawCubeProjection(false)
// == CAMERA CALIBRATION == // == CAMERA CALIBRATION ==
// If you do not manually specify calibration parameters, the SDK will attempt // If you do not manually specify calibration parameters, the SDK will attempt
@@ -220,14 +222,25 @@ public class ConceptAprilTag extends LinearOpMode {
// Step through the list of detections and display info for each one. // Step through the list of detections and display info for each one.
for (AprilTagDetection detection : currentDetections) { for (AprilTagDetection detection : currentDetections) {
if (detection.metadata != null) { if (detection instanceof AprilTagSingleDetection) {
telemetry.addLine(String.format("\n==== (ID %d) %s", detection.id, detection.metadata.name)); AprilTagSingleDetection singleDet = (AprilTagSingleDetection) detection;
if (singleDet.metadata != null) {
telemetry.addLine(String.format("\n==== (ID %d) %s", singleDet.id, singleDet.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", singleDet.id));
telemetry.addLine(String.format("Center %6.0f %6.0f (pixels)", singleDet.center.x, singleDet.center.y));
}
} else {
AprilTagClusterDetection clusterDet = (AprilTagClusterDetection) detection;
telemetry.addLine(String.format("\n==== Tag Cluster (%s)", clusterDet.metadata.name));
telemetry.addLine(String.format("Percent tags found: %d", clusterDet.percentClusterFound));
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("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("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)); 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 for() loop
@@ -36,8 +36,10 @@ import org.firstinspires.ftc.robotcore.external.hardware.camera.BuiltinCameraDir
import org.firstinspires.ftc.robotcore.external.hardware.camera.CameraCompatibilityManager; import org.firstinspires.ftc.robotcore.external.hardware.camera.CameraCompatibilityManager;
import org.firstinspires.ftc.robotcore.external.hardware.camera.WebcamName; import org.firstinspires.ftc.robotcore.external.hardware.camera.WebcamName;
import org.firstinspires.ftc.vision.VisionPortal; import org.firstinspires.ftc.vision.VisionPortal;
import org.firstinspires.ftc.vision.apriltag.AprilTagClusterDetection;
import org.firstinspires.ftc.vision.apriltag.AprilTagDetection; import org.firstinspires.ftc.vision.apriltag.AprilTagDetection;
import org.firstinspires.ftc.vision.apriltag.AprilTagProcessor; import org.firstinspires.ftc.vision.apriltag.AprilTagProcessor;
import org.firstinspires.ftc.vision.apriltag.AprilTagSingleDetection;
import java.util.List; import java.util.List;
@@ -45,6 +47,8 @@ import java.util.List;
* This OpMode illustrates the basics of AprilTag recognition and pose estimation, using * This OpMode illustrates the basics of AprilTag recognition and pose estimation, using
* the easy way. * the easy way.
* *
* Note: See ConceptAprilTag.java for how to add a camera compatibility quirk
*
* For an introduction to AprilTags, see the FTC-DOCS link below: * 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 * https://ftc-docs.firstinspires.org/en/latest/apriltag/vision_portal/apriltag_intro/apriltag-intro.html
* *
@@ -78,33 +82,10 @@ public class ConceptAprilTagEasy extends LinearOpMode {
*/ */
private VisionPortal visionPortal; private VisionPortal visionPortal;
// To find the VID/PID for a camera:
//
// Linux: open a terminal, run "lsusb", locate the line for your camera,
// and find the section that resembles "ID 1d6b:0002"; this is VID:PID
//
// OSX: open a terminal, run "system_profiler SPUSBDataType", locate the
// section for your camera, and find the "Product ID:" and "Vendor ID:"
// listings in the output
//
// Windows: open a PowerShell, run:
// Get-PnpDevice -PresentOnly | Where-Object { $_.InstanceId -like 'USB*' } | Select-Object FriendlyName, InstanceId
// and locate the line for your camera. The VID and PID is listed directly in the line.
static final int VENDOR_ID_SUNPLUS_INNOVATION_TECHNOLOGY = 0x1BCF;
static final int PRODUCT_ID_ARDUCAM_OV5648 = 0x284C;
@Override @Override
public void runOpMode() { public void runOpMode() {
// Demonstrate how to add a camera compatibility quirk // See ConceptAprilTag.java for how to add a camera compatibility quirk
// these can sometimes be needed if a camera behaves poorly.
// Quirks have no effect unless the camera you are using matches the specified VID/PID
CameraCompatibilityManager.getInstance()
.addQuirk(
VENDOR_ID_SUNPLUS_INNOVATION_TECHNOLOGY,
PRODUCT_ID_ARDUCAM_OV5648,
CameraCompatibilityManager.Quirk.AVOID_LIB_USB_RESET_DEVICE);
initAprilTag(); initAprilTag();
// Wait for the DS start button to be touched. // Wait for the DS start button to be touched.
@@ -165,14 +146,25 @@ public class ConceptAprilTagEasy extends LinearOpMode {
// Step through the list of detections and display info for each one. // Step through the list of detections and display info for each one.
for (AprilTagDetection detection : currentDetections) { for (AprilTagDetection detection : currentDetections) {
if (detection.metadata != null) { if (detection instanceof AprilTagSingleDetection) {
telemetry.addLine(String.format("\n==== (ID %d) %s", detection.id, detection.metadata.name)); AprilTagSingleDetection singleDet = (AprilTagSingleDetection) detection;
if (singleDet.metadata != null) {
telemetry.addLine(String.format("\n==== (ID %d) %s", singleDet.id, singleDet.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", singleDet.id));
telemetry.addLine(String.format("Center %6.0f %6.0f (pixels)", singleDet.center.x, singleDet.center.y));
}
} else {
AprilTagClusterDetection clusterDet = (AprilTagClusterDetection) detection;
telemetry.addLine(String.format("\n==== Tag Cluster (%s)", clusterDet.metadata.name));
telemetry.addLine(String.format("Percent tags found: %d", clusterDet.percentClusterFound));
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("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("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)); 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 for() loop
@@ -43,6 +43,7 @@ import org.firstinspires.ftc.robotcore.external.navigation.YawPitchRollAngles;
import org.firstinspires.ftc.vision.VisionPortal; import org.firstinspires.ftc.vision.VisionPortal;
import org.firstinspires.ftc.vision.apriltag.AprilTagDetection; import org.firstinspires.ftc.vision.apriltag.AprilTagDetection;
import org.firstinspires.ftc.vision.apriltag.AprilTagProcessor; import org.firstinspires.ftc.vision.apriltag.AprilTagProcessor;
import org.firstinspires.ftc.vision.apriltag.AprilTagSingleDetection;
import java.util.List; import java.util.List;
@@ -177,7 +178,7 @@ public class ConceptAprilTagLocalization extends LinearOpMode {
aprilTag = new AprilTagProcessor.Builder() aprilTag = new AprilTagProcessor.Builder()
// The following default settings are available to un-comment and edit as needed. // The following default settings are available to un-comment and edit as needed.
//.setDrawAxes(false) //.setDrawAxes(true) // changed in V12.0
//.setDrawCubeProjection(false) //.setDrawCubeProjection(false)
//.setDrawTagOutline(true) //.setDrawTagOutline(true)
//.setTagFamily(AprilTagProcessor.TagFamily.TAG_36h11) //.setTagFamily(AprilTagProcessor.TagFamily.TAG_36h11)
@@ -247,22 +248,23 @@ public class ConceptAprilTagLocalization extends LinearOpMode {
// Step through the list of detections and display info for each one. // Step through the list of detections and display info for each one.
for (AprilTagDetection detection : currentDetections) { for (AprilTagDetection detection : currentDetections) {
if (detection.metadata != null) { if (detection instanceof AprilTagSingleDetection) {
telemetry.addLine(String.format("\n==== (ID %d) %s", detection.id, detection.metadata.name)); AprilTagSingleDetection singleDet = (AprilTagSingleDetection) detection;
// Only use tags that don't have Obelisk in them
if (!detection.metadata.name.contains("Obelisk")) { if (singleDet.metadata != null) {
telemetry.addLine(String.format("XYZ %6.1f %6.1f %6.1f (inch)", telemetry.addLine(String.format("\n==== (ID %d) %s", singleDet.id, singleDet.metadata.name));
telemetry.addLine(String.format("Robot XYZ %6.1f %6.1f %6.1f (inch)",
detection.robotPose.getPosition().x, detection.robotPose.getPosition().x,
detection.robotPose.getPosition().y, detection.robotPose.getPosition().y,
detection.robotPose.getPosition().z)); detection.robotPose.getPosition().z));
telemetry.addLine(String.format("PRY %6.1f %6.1f %6.1f (deg)", telemetry.addLine(String.format("Robot PRY %6.1f %6.1f %6.1f (deg)",
detection.robotPose.getOrientation().getPitch(AngleUnit.DEGREES), detection.robotPose.getOrientation().getPitch(AngleUnit.DEGREES),
detection.robotPose.getOrientation().getRoll(AngleUnit.DEGREES), detection.robotPose.getOrientation().getRoll(AngleUnit.DEGREES),
detection.robotPose.getOrientation().getYaw(AngleUnit.DEGREES))); detection.robotPose.getOrientation().getYaw(AngleUnit.DEGREES)));
} else {
telemetry.addLine(String.format("\n==== (ID %d) Unknown", singleDet.id));
telemetry.addLine(String.format("Center %6.0f %6.0f (pixels)", singleDet.center.x, singleDet.center.y));
} }
} 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 for() loop
@@ -37,8 +37,10 @@ import org.firstinspires.ftc.robotcore.external.hardware.camera.CameraName;
import org.firstinspires.ftc.robotcore.external.hardware.camera.WebcamName; import org.firstinspires.ftc.robotcore.external.hardware.camera.WebcamName;
import org.firstinspires.ftc.vision.VisionPortal; import org.firstinspires.ftc.vision.VisionPortal;
import org.firstinspires.ftc.vision.VisionPortal.CameraState; import org.firstinspires.ftc.vision.VisionPortal.CameraState;
import org.firstinspires.ftc.vision.apriltag.AprilTagClusterDetection;
import org.firstinspires.ftc.vision.apriltag.AprilTagDetection; import org.firstinspires.ftc.vision.apriltag.AprilTagDetection;
import org.firstinspires.ftc.vision.apriltag.AprilTagProcessor; import org.firstinspires.ftc.vision.apriltag.AprilTagProcessor;
import org.firstinspires.ftc.vision.apriltag.AprilTagSingleDetection;
import java.util.List; import java.util.List;
@@ -153,14 +155,25 @@ public class ConceptAprilTagSwitchableCameras extends LinearOpMode {
// Step through the list of detections and display info for each one. // Step through the list of detections and display info for each one.
for (AprilTagDetection detection : currentDetections) { for (AprilTagDetection detection : currentDetections) {
if (detection.metadata != null) { if (detection instanceof AprilTagSingleDetection) {
telemetry.addLine(String.format("\n==== (ID %d) %s", detection.id, detection.metadata.name)); AprilTagSingleDetection singleDet = (AprilTagSingleDetection) detection;
if (singleDet.metadata != null) {
telemetry.addLine(String.format("\n==== (ID %d) %s", singleDet.id, singleDet.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", singleDet.id));
telemetry.addLine(String.format("Center %6.0f %6.0f (pixels)", singleDet.center.x, singleDet.center.y));
}
} else {
AprilTagClusterDetection clusterDet = (AprilTagClusterDetection) detection;
telemetry.addLine(String.format("\n==== Tag Cluster (%s)", clusterDet.metadata.name));
telemetry.addLine(String.format("Percent tags found: %d", clusterDet.percentClusterFound));
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("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("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)); 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 for() loop
@@ -39,25 +39,32 @@ import org.firstinspires.ftc.robotcore.external.hardware.camera.WebcamName;
import org.firstinspires.ftc.robotcore.external.hardware.camera.controls.ExposureControl; import org.firstinspires.ftc.robotcore.external.hardware.camera.controls.ExposureControl;
import org.firstinspires.ftc.robotcore.external.hardware.camera.controls.GainControl; import org.firstinspires.ftc.robotcore.external.hardware.camera.controls.GainControl;
import org.firstinspires.ftc.vision.VisionPortal; import org.firstinspires.ftc.vision.VisionPortal;
import org.firstinspires.ftc.vision.apriltag.AprilTagClusterDetection;
import org.firstinspires.ftc.vision.apriltag.AprilTagDetection; import org.firstinspires.ftc.vision.apriltag.AprilTagDetection;
import org.firstinspires.ftc.vision.apriltag.AprilTagProcessor; import org.firstinspires.ftc.vision.apriltag.AprilTagProcessor;
import org.firstinspires.ftc.vision.apriltag.AprilTagSingleDetection;
import java.util.List; import java.util.List;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
/* /*
* This OpMode illustrates using a camera to locate and drive towards a specific AprilTag. * This OpMode illustrates using a camera to locate and drive towards a specific AprilTag or AprilTag Cluster
* A "Cluster" is a group of Apriltags that share a common origin, and are identified by name.
* The code assumes a Holonomic (Mecanum or X Drive) Robot. * The code assumes a Holonomic (Mecanum or X Drive) Robot.
* *
* For an introduction to AprilTags, see the ftc-docs link below: * 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 * https://ftc-docs.firstinspires.org/en/latest/apriltag/vision_portal/apriltag_intro/apriltag-intro.html
* *
* When an AprilTag in the TagLibrary is detected, the SDK provides location and orientation of the tag, relative to the camera. * When an AprilTag/Cluster in the TagLibrary is detected, the SDK provides location and orientation of the target, relative to the camera.
* This information is provided in the "ftcPose" member of the returned "detection", and is explained in the ftc-docs page linked below. * This information is provided in the "ftcPose" member of the returned "detection", and is explained in the ftc-docs page linked below.
* https://ftc-docs.firstinspires.org/apriltag-detection-values * https://ftc-docs.firstinspires.org/apriltag-detection-values
* *
* The drive goal is to rotate to keep the Tag centered in the camera, while strafing to be directly in front of the tag, and * For a single tag, the "Drive Target" is the center of the Tag. For a cluster of tags, the "Drive Target" will be the
* driving towards the tag to achieve the desired distance. * (0,0,0) ORIGIN of the cluster, which may have been positioned somewhere other than the center of the cluster in order
* to help to locate a game objective.
*
* The driving goal is to rotate to keep the Target centered in the camera, while strafing to be directly in front of the target,
* and driving towards the target to achieve the desired distance.
* To reduce any motion blur (which will interrupt the detection process) the Camera exposure is reduced to a very low value (5mS) * To reduce any motion blur (which will interrupt the detection process) the Camera exposure is reduced to a very low value (5mS)
* You can determine the best Exposure and Gain values by using the ConceptAprilTagOptimizeExposure OpMode in this Samples folder. * You can determine the best Exposure and Gain values by using the ConceptAprilTagOptimizeExposure OpMode in this Samples folder.
* *
@@ -73,9 +80,9 @@ import java.util.concurrent.TimeUnit;
* Release the Left Bumper to return to manual driving mode. * Release the Left Bumper to return to manual driving mode.
* *
* Under "Drive To Target" mode, the robot has three goals: * Under "Drive To Target" mode, the robot has three goals:
* 1) Turn the robot to always keep the Tag centered on the camera frame. (Use the Target Bearing to turn the robot.) * 1) Turn the robot to always keep the Target centered on the camera frame. (Use the Target Bearing to turn the robot.)
* 2) Strafe the robot towards the centerline of the Tag, so it approaches directly in front of the tag. (Use the Target Yaw to strafe the robot) * 2) Strafe the robot towards the centerline of the Target, so it approaches directly in front of the tag. (Use the Target Yaw to strafe the robot)
* 3) Drive towards the Tag to get to the desired distance. (Use Tag Range to drive the robot forward/backward) * 3) Drive towards the Target to get to the desired distance. (Use TargetRange to drive the robot forward/backward)
* *
* Use DESIRED_DISTANCE to set how close you want the robot to get to the target. * Use DESIRED_DISTANCE to set how close you want the robot to get to the target.
* Speed and Turn sensitivity can be adjusted using the SPEED_GAIN, STRAFE_GAIN and TURN_GAIN constants. * Speed and Turn sensitivity can be adjusted using the SPEED_GAIN, STRAFE_GAIN and TURN_GAIN constants.
@@ -90,7 +97,7 @@ import java.util.concurrent.TimeUnit;
public class RobotAutoDriveToAprilTagOmni extends LinearOpMode public class RobotAutoDriveToAprilTagOmni extends LinearOpMode
{ {
// Adjust these numbers to suit your robot. // Adjust these numbers to suit your robot.
final double DESIRED_DISTANCE = 12.0; // this is how close the camera should get to the target (inches) final double DESIRED_DISTANCE = 30.0; // this is how close the camera should get to the target (inches)
// Set the GAIN constants to control the relationship between the measured position error, and how much power is // 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. // applied to the drive motors to correct the error.
@@ -99,24 +106,31 @@ public class RobotAutoDriveToAprilTagOmni extends LinearOpMode
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 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 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_SPEED = 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_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) final double MAX_AUTO_TURN = 0.3; // Clip the turn speed to this max value (adjust for your robot)
private DcMotor frontLeftDrive = null; // Used to control the left front drive wheel private DcMotor frontLeftDrive = null; // Used to control the left front drive wheel
private DcMotor frontRightDrive = null; // Used to control the right front drive wheel private DcMotor frontRightDrive = null; // Used to control the right front drive wheel
private DcMotor backLeftDrive = null; // Used to control the left back drive wheel private DcMotor backLeftDrive = null; // Used to control the left back drive wheel
private DcMotor backRightDrive = null; // Used to control the right back drive wheel private DcMotor backRightDrive = null; // Used to control the right back drive wheel
private static final boolean USE_WEBCAM = true; // Set true to use a webcam, or false for a phone camera private final boolean USE_WEBCAM = true; // Set true to use a webcam, or false for a phone camera
private static final int DESIRED_TAG_ID = -1; // Choose the tag you want to approach or set to -1 for ANY tag. private final int DESIRED_TAG_ID = -1; // The tag you want to approach, or set to -1 for ANY tag.
private final String DESIRED_CLUSTER_NAME = null; // The cluster name you want to approach, or set null for ANY cluster.
private VisionPortal visionPortal; // Used to manage the video source. private VisionPortal visionPortal; // Used to manage the video source.
private AprilTagProcessor aprilTag; // Used for managing the AprilTag detection process. private AprilTagProcessor aprilTag; // Used for managing the AprilTag detection process.
private AprilTagDetection desiredTag = null; // Used to hold the data for a detected AprilTag
private boolean targetFound = false; // Set to true when an AprilTag/Cluster target is detected
private String targetName = "none";
private int targetID = 0;
private double targetRange = 0;
private double targetBearing = 0;
private double targetYaw = 0;
@Override public void runOpMode() @Override public void runOpMode()
{ {
boolean targetFound = false; // Set to true when an AprilTag target is detected
double drive = 0; // Desired forward power/speed (-1 to +1) double drive = 0; // Desired forward power/speed (-1 to +1)
double strafe = 0; // Desired strafe power/speed (-1 to +1) double strafe = 0; // Desired strafe power/speed (-1 to +1)
double turn = 0; // Desired turning power/speed (-1 to +1) double turn = 0; // Desired turning power/speed (-1 to +1)
@@ -152,36 +166,57 @@ public class RobotAutoDriveToAprilTagOmni extends LinearOpMode
while (opModeIsActive()) while (opModeIsActive())
{ {
targetFound = false; targetFound = false;
desiredTag = null;
// Step through the list of detected tags and look for a matching tag // Step through the list of detected tags and look for a matching tag
List<AprilTagDetection> currentDetections = aprilTag.getDetections(); List<AprilTagDetection> currentDetections = aprilTag.getDetections();
for (AprilTagDetection detection : currentDetections) { for (AprilTagDetection detection : currentDetections) {
// Look to see if we have size info on this tag.
if (detection.metadata != null) { if (detection instanceof AprilTagSingleDetection) {
// Check to see if we want to track towards this tag. AprilTagSingleDetection singleDetection = (AprilTagSingleDetection) detection;
if ((DESIRED_TAG_ID < 0) || (detection.id == DESIRED_TAG_ID)) {
// Yes, we want to use this tag. // Look to see if we have size info on this tag.
targetFound = true; if (singleDetection.metadata != null) {
desiredTag = detection; // Check to see if we want to track towards this tag.
break; // don't look any further. if ((DESIRED_TAG_ID < 0) || (singleDetection.id == DESIRED_TAG_ID)) {
// Yes, we want to use this tag.
targetName = singleDetection.metadata.name;
targetID = singleDetection.id;
targetRange = singleDetection.ftcPose.range;
targetBearing = singleDetection.ftcPose.bearing;
targetYaw = singleDetection.ftcPose.yaw;
targetFound = true;
break; // don't look any further.
} else {
// This tag is in the library, but we do not want to track it right now.
telemetry.addData("Skipping", "Tag ID %d is not desired", singleDetection.id);
}
} else { } else {
// This tag is in the library, but we do not want to track it right now. // This tag is NOT in the library, so we don't have enough information to track to it.
telemetry.addData("Skipping", "Tag ID %d is not desired", detection.id); telemetry.addData("Unknown", "Tag ID %d is not in TagLibrary", singleDetection.id);
} }
} else { } else {
// This tag is NOT in the library, so we don't have enough information to track to it. AprilTagClusterDetection clusterDet = (AprilTagClusterDetection) detection;
telemetry.addData("Unknown", "Tag ID %d is not in TagLibrary", detection.id);
if (DESIRED_CLUSTER_NAME == null || clusterDet.metadata.shortName.equals(DESIRED_CLUSTER_NAME) ) {
// Yes, we want to use this tag.
targetName = clusterDet.metadata.shortName;
targetID = -1;
targetRange = clusterDet.ftcPose.range;
targetBearing = clusterDet.ftcPose.bearing;
targetYaw = clusterDet.ftcPose.yaw;
targetFound = true;
break; // don't look any further.
}
} }
} }
// Tell the driver what we see, and what to do. // Tell the driver what we see, and what to do.
if (targetFound) { if (targetFound) {
telemetry.addData("\n>","HOLD Left-Bumper to Drive to Target\n"); telemetry.addData("\n>","HOLD Left-Bumper to Drive to Target\n");
telemetry.addData("Found", "ID %d (%s)", desiredTag.id, desiredTag.metadata.name); telemetry.addData("Found", "ID %d (%s)", targetID, targetName);
telemetry.addData("Range", "%5.1f inches", desiredTag.ftcPose.range); telemetry.addData("Range", "%5.1f inches", targetRange);
telemetry.addData("Bearing","%3.0f degrees", desiredTag.ftcPose.bearing); telemetry.addData("Bearing","%3.0f degrees", targetBearing);
telemetry.addData("Yaw","%3.0f degrees", desiredTag.ftcPose.yaw); telemetry.addData("Yaw","%3.0f degrees", targetYaw);
} else { } else {
telemetry.addData("\n>","Drive using joysticks to find valid target\n"); telemetry.addData("\n>","Drive using joysticks to find valid target\n");
} }
@@ -190,9 +225,9 @@ public class RobotAutoDriveToAprilTagOmni extends LinearOpMode
if (gamepad1.left_bumper && targetFound) { if (gamepad1.left_bumper && targetFound) {
// Determine heading, range and Yaw (tag image rotation) error so we can use them to control the robot automatically. // Determine heading, range and Yaw (tag image rotation) error so we can use them to control the robot automatically.
double rangeError = (desiredTag.ftcPose.range - DESIRED_DISTANCE); double rangeError = targetRange - DESIRED_DISTANCE;
double headingError = desiredTag.ftcPose.bearing; double headingError = targetBearing;
double yawError = desiredTag.ftcPose.yaw; double yawError = targetYaw;
// Use the speed and turn "gains" to calculate how we want the robot to move. // Use the speed and turn "gains" to calculate how we want the robot to move.
drive = Range.clip(rangeError * SPEED_GAIN, -MAX_AUTO_SPEED, MAX_AUTO_SPEED); drive = Range.clip(rangeError * SPEED_GAIN, -MAX_AUTO_SPEED, MAX_AUTO_SPEED);
@@ -201,7 +236,6 @@ public class RobotAutoDriveToAprilTagOmni extends LinearOpMode
telemetry.addData("Auto","Drive %5.2f, Strafe %5.2f, Turn %5.2f ", drive, strafe, turn); telemetry.addData("Auto","Drive %5.2f, Strafe %5.2f, Turn %5.2f ", drive, strafe, turn);
} else { } else {
// drive using manual POV Joystick mode. Slow things down to make the robot more controlable. // drive using manual POV Joystick mode. Slow things down to make the robot more controlable.
drive = -gamepad1.left_stick_y / 2.0; // Reduce drive rate to 50%. drive = -gamepad1.left_stick_y / 2.0; // Reduce drive rate to 50%.
strafe = -gamepad1.left_stick_x / 2.0; // Reduce strafe rate to 50%. strafe = -gamepad1.left_stick_x / 2.0; // Reduce strafe rate to 50%.
@@ -218,11 +252,8 @@ public class RobotAutoDriveToAprilTagOmni extends LinearOpMode
/** /**
* Move robot according to desired axes motions * Move robot according to desired axes motions
* <p>
* Positive X is forward * Positive X is forward
* <p>
* Positive Y is strafe left * Positive Y is strafe left
* <p>
* Positive Yaw is counter-clockwise * Positive Yaw is counter-clockwise
*/ */
public void moveRobot(double x, double y, double yaw) { public void moveRobot(double x, double y, double yaw) {
@@ -39,44 +39,50 @@ import org.firstinspires.ftc.robotcore.external.hardware.camera.WebcamName;
import org.firstinspires.ftc.robotcore.external.hardware.camera.controls.ExposureControl; import org.firstinspires.ftc.robotcore.external.hardware.camera.controls.ExposureControl;
import org.firstinspires.ftc.robotcore.external.hardware.camera.controls.GainControl; import org.firstinspires.ftc.robotcore.external.hardware.camera.controls.GainControl;
import org.firstinspires.ftc.vision.VisionPortal; import org.firstinspires.ftc.vision.VisionPortal;
import org.firstinspires.ftc.vision.apriltag.AprilTagClusterDetection;
import org.firstinspires.ftc.vision.apriltag.AprilTagDetection; import org.firstinspires.ftc.vision.apriltag.AprilTagDetection;
import org.firstinspires.ftc.vision.apriltag.AprilTagProcessor; import org.firstinspires.ftc.vision.apriltag.AprilTagProcessor;
import org.firstinspires.ftc.vision.apriltag.AprilTagSingleDetection;
import java.util.List; import java.util.List;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
/* /*
* This OpMode illustrates using a camera to locate and drive towards a specific AprilTag. * This OpMode illustrates using a camera to locate and drive towards a specific AprilTag or AprilTag Cluster
* The code assumes a basic two-wheel (Tank) Robot Drivetrain * A "Cluster" is a group of Apriltags that share a common origin, and are identified by name.
* The code assumes a basic two-motor Tank (differential) drive robot.
* *
* For an introduction to AprilTags, see the ftc-docs link below: * 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 * https://ftc-docs.firstinspires.org/en/latest/apriltag/vision_portal/apriltag_intro/apriltag-intro.html
* *
* When an AprilTag in the TagLibrary is detected, the SDK provides location and orientation of the tag, relative to the camera. * When an AprilTag/Cluster in the TagLibrary is detected, the SDK provides location and orientation of the target, relative to the camera.
* This information is provided in the "ftcPose" member of the returned "detection", and is explained in the ftc-docs page linked below. * This information is provided in the "ftcPose" member of the returned "detection", and is explained in the ftc-docs page linked below.
* https://ftc-docs.firstinspires.org/apriltag-detection-values * https://ftc-docs.firstinspires.org/apriltag-detection-values
* *
* The driving goal is to rotate to keep the tag centered in the camera, while driving towards the tag to achieve the desired distance. * For a single tag, the "Drive Target" is the center of the Tag. For a cluster of tags, the "Drive Target" will be the
* To reduce any motion blur (which will interrupt the detection process) the Camera exposure is reduced to a very low value (5mS) * (0,0,0) ORIGIN of the cluster, which may have been positioned somewhere other than the center of the cluster in order
* You can determine the best exposure and gain values by using the ConceptAprilTagOptimizeExposure OpMode in this Samples folder. * to help to locate a game objective.
* *
* The code assumes a Robot Configuration with motors named left_drive and right_drive. * The driving goal is to rotate to keep the Target centered in the camera, while driving towards the target to achieve the desired distance.
* The motor directions must be set so a positive power goes forward on both wheels; * To reduce any motion blur (which will interrupt the detection process) the Camera exposure is reduced to a very low value (5mS)
* This sample assumes that the default AprilTag Library (usually for the current season) is being loaded by default * You can determine the best Exposure and Gain values by using the ConceptAprilTagOptimizeExposure OpMode in this Samples folder.
*
* 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 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. * 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. * Under manual control, the left stick will move forward/back & left/right. The right stick will rotate the robot.
* This is called POV Joystick mode, different than Tank Drive (where each joystick controls a wheel).
*
* Manually drive the robot until it displays Target data on the Driver Station. * Manually drive the robot until it displays Target data on the Driver Station.
*
* Press and hold the *Left Bumper* to enable the automatic "Drive to target" mode. * Press and hold the *Left Bumper* to enable the automatic "Drive to target" mode.
* Release the Left Bumper to return to manual driving mode. * Release the Left Bumper to return to manual driving mode.
* *
* Under "Drive To Target" mode, the robot has two goals: * Under "Drive To Target" mode, the robot has two goals:
* 1) Turn the robot to always keep the Tag centered on the camera frame. (Use the Target Bearing to turn the robot.) * 1) Turn the robot to always keep the Target centered on the camera frame. (Use the Target Bearing to turn the robot.)
* 2) Drive towards the Tag to get to the desired distance. (Use Tag Range to drive the robot forward/backward) * 2) Drive towards the Target to get to the desired distance. (Use TargetRange to drive the robot forward/backward)
* *
* Use DESIRED_DISTANCE to set how close you want the robot to get to the target. * Use DESIRED_DISTANCE to set how close you want the robot to get to the target.
* Speed and Turn sensitivity can be adjusted using the SPEED_GAIN and TURN_GAIN constants. * Speed and Turn sensitivity can be adjusted using the SPEED_GAIN and TURN_GAIN constants.
* *
* Use Android Studio to Copy this Class, and Paste it into the TeamCode/src/main/java/org/firstinspires/ftc/teamcode folder. * Use Android Studio to Copy this Class, and Paste it into the TeamCode/src/main/java/org/firstinspires/ftc/teamcode folder.
@@ -89,7 +95,7 @@ import java.util.concurrent.TimeUnit;
public class RobotAutoDriveToAprilTagTank extends LinearOpMode public class RobotAutoDriveToAprilTagTank extends LinearOpMode
{ {
// Adjust these numbers to suit your robot. // Adjust these numbers to suit your robot.
final double DESIRED_DISTANCE = 12.0; // this is how close the camera should get to the target (inches) final double DESIRED_DISTANCE = 30.0; // this is how close the camera should get to the target (inches)
// Set the GAIN constants to control the relationship between the measured position error, and how much power is // 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. // applied to the drive motors to correct the error.
@@ -103,15 +109,22 @@ public class RobotAutoDriveToAprilTagTank extends LinearOpMode
private DcMotor leftDrive = null; // Used to control the left drive wheel private DcMotor leftDrive = null; // Used to control the left drive wheel
private DcMotor rightDrive = null; // Used to control the right drive wheel private DcMotor rightDrive = null; // Used to control the right drive wheel
private static final boolean USE_WEBCAM = true; // Set true to use a webcam, or false for a phone camera private final boolean USE_WEBCAM = true; // Set true to use a webcam, or false for a phone camera
private static final int DESIRED_TAG_ID = -1; // Choose the tag you want to approach or set to -1 for ANY tag. private final int DESIRED_TAG_ID = -1; // The tag you want to approach, or set to -1 for ANY tag.
private final String DESIRED_CLUSTER_NAME = null; // The cluster name you want to approach, or set null for ANY cluster.
private VisionPortal visionPortal; // Used to manage the video source. private VisionPortal visionPortal; // Used to manage the video source.
private AprilTagProcessor aprilTag; // Used for managing the AprilTag detection process. private AprilTagProcessor aprilTag; // Used for managing the AprilTag detection process.
private AprilTagDetection desiredTag = null; // Used to hold the data for a detected AprilTag
private boolean targetFound = false; // Set to true when an AprilTag/Cluster target is detected
private String targetName = "none";
private int targetID = 0;
private double targetRange = 0;
private double targetBearing = 0;
private double targetYaw = 0;
@Override public void runOpMode() @Override public void runOpMode()
{ {
boolean targetFound = false; // Set to true when an AprilTag target is detected
double drive = 0; // Desired forward power/speed (-1 to +1) +ve is forward double drive = 0; // Desired forward power/speed (-1 to +1) +ve is forward
double turn = 0; // Desired turning power/speed (-1 to +1) +ve is CounterClockwise double turn = 0; // Desired turning power/speed (-1 to +1) +ve is CounterClockwise
@@ -142,35 +155,57 @@ public class RobotAutoDriveToAprilTagTank extends LinearOpMode
while (opModeIsActive()) while (opModeIsActive())
{ {
targetFound = false; targetFound = false;
desiredTag = null;
// Step through the list of detected tags and look for a matching tag // Step through the list of detected tags and look for a matching tag
List<AprilTagDetection> currentDetections = aprilTag.getDetections(); List<AprilTagDetection> currentDetections = aprilTag.getDetections();
for (AprilTagDetection detection : currentDetections) { for (AprilTagDetection detection : currentDetections) {
// Look to see if we have size info on this tag.
if (detection.metadata != null) { if (detection instanceof AprilTagSingleDetection) {
// Check to see if we want to track towards this tag. AprilTagSingleDetection singleDetection = (AprilTagSingleDetection) detection;
if ((DESIRED_TAG_ID < 0) || (detection.id == DESIRED_TAG_ID)) {
// Yes, we want to use this tag. // Look to see if we have size info on this tag.
targetFound = true; if (singleDetection.metadata != null) {
desiredTag = detection; // Check to see if we want to track towards this tag.
break; // don't look any further. if ((DESIRED_TAG_ID < 0) || (singleDetection.id == DESIRED_TAG_ID)) {
// Yes, we want to use this tag.
targetName = singleDetection.metadata.name;
targetID = singleDetection.id;
targetRange = singleDetection.ftcPose.range;
targetBearing = singleDetection.ftcPose.bearing;
targetYaw = singleDetection.ftcPose.yaw;
targetFound = true;
break; // don't look any further.
} else {
// This tag is in the library, but we do not want to track it right now.
telemetry.addData("Skipping", "Tag ID %d is not desired", singleDetection.id);
}
} else { } else {
// This tag is in the library, but we do not want to track it right now. // This tag is NOT in the library, so we don't have enough information to track to it.
telemetry.addData("Skipping", "Tag ID %d is not desired", detection.id); telemetry.addData("Unknown", "Tag ID %d is not in TagLibrary", singleDetection.id);
}
} else {
AprilTagClusterDetection clusterDet = (AprilTagClusterDetection) detection;
if (DESIRED_CLUSTER_NAME == null || clusterDet.metadata.shortName.equals(DESIRED_CLUSTER_NAME) ) {
// Yes, we want to use this tag.
targetName = clusterDet.metadata.shortName;
targetID = -1;
targetRange = clusterDet.ftcPose.range;
targetBearing = clusterDet.ftcPose.bearing;
targetYaw = clusterDet.ftcPose.yaw;
targetFound = true;
break; // don't look any further.
} }
} else {
// This tag is NOT in the library, so we don't have enough information to track to it.
telemetry.addData("Unknown", "Tag ID %d is not in TagLibrary", detection.id);
} }
} }
// Tell the driver what we see, and what to do. // Tell the driver what we see, and what to do.
if (targetFound) { if (targetFound) {
telemetry.addData("\n>","HOLD Left-Bumper to Drive to Target\n"); telemetry.addData("\n>","HOLD Left-Bumper to Drive to Target\n");
telemetry.addData("Found", "ID %d (%s)", desiredTag.id, desiredTag.metadata.name); telemetry.addData("Found", "ID %d (%s)", targetID, targetName);
telemetry.addData("Range", "%5.1f inches", desiredTag.ftcPose.range); telemetry.addData("Range", "%5.1f inches", targetRange);
telemetry.addData("Bearing","%3.0f degrees", desiredTag.ftcPose.bearing); telemetry.addData("Bearing","%3.0f degrees", targetBearing);
telemetry.addData("Yaw","%3.0f degrees", targetYaw);
} else { } else {
telemetry.addData("\n>","Drive using joysticks to find valid target\n"); telemetry.addData("\n>","Drive using joysticks to find valid target\n");
} }
@@ -179,8 +214,8 @@ public class RobotAutoDriveToAprilTagTank extends LinearOpMode
if (gamepad1.left_bumper && targetFound) { if (gamepad1.left_bumper && targetFound) {
// Determine heading and range error so we can use them to control the robot automatically. // Determine heading and range error so we can use them to control the robot automatically.
double rangeError = (desiredTag.ftcPose.range - DESIRED_DISTANCE); double rangeError = targetRange - DESIRED_DISTANCE;
double headingError = desiredTag.ftcPose.bearing; double headingError = targetBearing;
// Use the speed and turn "gains" to calculate how we want the robot to move. Clip it to the maximum // Use the speed and turn "gains" to calculate how we want the robot to move. Clip it to the maximum
drive = Range.clip(rangeError * SPEED_GAIN, -MAX_AUTO_SPEED, MAX_AUTO_SPEED); drive = Range.clip(rangeError * SPEED_GAIN, -MAX_AUTO_SPEED, MAX_AUTO_SPEED);
@@ -188,7 +223,6 @@ public class RobotAutoDriveToAprilTagTank extends LinearOpMode
telemetry.addData("Auto","Drive %5.2f, Turn %5.2f", drive, turn); telemetry.addData("Auto","Drive %5.2f, Turn %5.2f", drive, turn);
} else { } else {
// drive using manual POV Joystick mode. // drive using manual POV Joystick mode.
drive = -gamepad1.left_stick_y / 2.0; // Reduce drive rate to 50%. drive = -gamepad1.left_stick_y / 2.0; // Reduce drive rate to 50%.
turn = -gamepad1.right_stick_x / 4.0; // Reduce turn rate to 25%. turn = -gamepad1.right_stick_x / 4.0; // Reduce turn rate to 25%.
@@ -204,9 +238,7 @@ public class RobotAutoDriveToAprilTagTank extends LinearOpMode
/** /**
* Move robot according to desired axes motions * Move robot according to desired axes motions
* <p>
* Positive X is forward * Positive X is forward
* <p>
* Positive Yaw is counter-clockwise * Positive Yaw is counter-clockwise
*/ */
public void moveRobot(double x, double yaw) { public void moveRobot(double x, double yaw) {
+50 -2
View File
@@ -1,12 +1,12 @@
## NOTICE ## NOTICE
This repository contains the public FTC SDK for the DECODE (2025-2026) competition season. This repository contains the public FTC SDK for the BIOBUZZ (2026-2027) competition season.
## Welcome! ## 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. 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.
## Requirements ## Requirements
To use this Android Studio project, you will need Android Studio Ladybug (2024.2) or later. To use this Android Studio project, you will need Android Studio Narwhal 3 Feature Drop or later.
To program your robot in Blocks or OnBot Java, you do not need Android Studio. To program your robot in Blocks or OnBot Java, you do not need Android Studio.
@@ -59,6 +59,54 @@ The readme.md file located in the [/TeamCode/src/main/java/org/firstinspires/ftc
# Release Information # Release Information
## Version 12.0 (20260907-090034)
### Breaking Changes
* The new AprilTag Cluster capability breaks legacy AprilTag OpModes resulting in compile errors for software that uses AprilTagDetection objects in both Android Studio and OnBot Java.
* Legacy AprilTag OpModes must be updated to check whether the returned AprilTag is a cluster or singleton,
and cast the returned detection into the correct type to access its elements. See below:
**Old method for AprilTag processing**
```
for (AprilTagDetection detection : currentDetections) {
// Do single Tag processing here
}
```
**New method for AprilTag Singleton/Cluster processing**
```
for (AprilTagDetection detection : currentDetections) {
if (detection instanceof AprilTagSingleDetection) {
AprilTagSingleDetection singleDet = (AprilTagSingleDetection) detection;
// Do single Tag processing here
} else {
AprilTagClusterDetection clusterDet = (AprilTagClusterDetection) detection;
// Do cluster Tag processing here
}
}
```
For more information about how to update your OpModes to fix the breaking change see: https://ftc-docs.firstinspires.org/apriltag-clusters
* About AprilTag clusters:
* Clusters are co-planar groups of two or more AprilTags wherein the position of each member tag is defined relative to a common origin
* This origin may be placed outside the bounds of the tags themselves to provide a more suitable "aiming" target
* Clusters are resilient to partial occlusion. Full 6DOF pose can be estimated from a cluster even if only a single member tag is visible. Of course, the more tags that are visible, the better and more stable the pose estimate will be
* All AprilTag samples have been updated to differentiate between standalone tags and clusters
### Enhancements
* Adds a tree view for robot configurations [issue 1821](https://github.com/FIRST-Tech-Challenge/FtcRobotController/issues/1821)
* Gamepad indicators on the Driver Station are now colored orange if the respective gamepads are connected to the Android generic gamepad driver instead of the Driver Station's usermode USB driver
* Updated AprilTag Library for BIOBUZZ. Notably, getCurrentGameTagLibrary() now returns BIOBUZZ tags.
* In BIOBUZZ, the Origin of each cluster is located in the center of the Cell opening for easy aiming.
* The Origin X,Y & Z Axes are now displayed by default on the preview image.
* <B>Unfortunately, since BIOBUZZ AprilTags move, they are not suitable for absolute Field Localization.</B>
* Supports OctoQuad MK2 firmware v3.1.0, which adds diagnostics parameters for the IMU and MCU uptime
### Bug Fixes
* Fixes issue [2078](https://github.com/FIRST-Tech-Challenge/FtcRobotController/issues/2078) where battery
voltage was not updated on driver station if OpMode did not send any telemetry.
## Version 11.2.1 (20260724-093406) ## Version 11.2.1 (20260724-093406)
### Bug Fixes ### Bug Fixes
+8 -8
View File
@@ -4,14 +4,14 @@ repositories {
} }
dependencies { dependencies {
implementation 'org.firstinspires.ftc:Inspection:11.2.1' implementation 'org.firstinspires.ftc:Inspection:12.0.0'
implementation 'org.firstinspires.ftc:Blocks:11.2.1' implementation 'org.firstinspires.ftc:Blocks:12.0.0'
implementation 'org.firstinspires.ftc:RobotCore:11.2.1' implementation 'org.firstinspires.ftc:RobotCore:12.0.0'
implementation 'org.firstinspires.ftc:RobotServer:11.2.1' implementation 'org.firstinspires.ftc:RobotServer:12.0.0'
implementation 'org.firstinspires.ftc:OnBotJava:11.2.1' implementation 'org.firstinspires.ftc:OnBotJava:12.0.0'
implementation 'org.firstinspires.ftc:Hardware:11.2.1' implementation 'org.firstinspires.ftc:Hardware:12.0.0'
implementation 'org.firstinspires.ftc:FtcCommon:11.2.1' implementation 'org.firstinspires.ftc:FtcCommon:12.0.0'
implementation 'org.firstinspires.ftc:Vision:11.2.1' implementation 'org.firstinspires.ftc:Vision:12.0.0'
implementation 'androidx.appcompat:appcompat:1.2.0' implementation 'androidx.appcompat:appcompat:1.2.0'
} }