/* | |
* Copyright (c) 2021 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. | |
*/ | |
package org.firstinspires.ftc.teamcode.auton; | |
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.openftc.apriltag.AprilTagDetection; | |
import org.openftc.easyopencv.OpenCvCamera; | |
import org.openftc.easyopencv.OpenCvCameraFactory; | |
import org.openftc.easyopencv.OpenCvCameraRotation; | |
import org.openftc.easyopencv.OpenCvInternalCamera; | |
import java.util.ArrayList; | |
@TeleOp | |
public class AprilTagAutonomousInitDetectionExample extends LinearOpMode | |
{ | |
OpenCvCamera camera; | |
AprilTagDetectionPipeline aprilTagDetectionPipeline; | |
static final double FEET_PER_METER = 3.28084; | |
// Lens intrinsics | |
// UNITS ARE PIXELS | |
// NOTE: this calibration is for the C920 webcam at 800x448. | |
// You will need to do your own calibration for other configurations! | |
double fx = 578.272; | |
double fy = 578.272; | |
double cx = 402.145; | |
double cy = 221.506; | |
// UNITS ARE METERS | |
double tagsize = 0.166; | |
// Tag ID 1,2,3 from the 36h11 family | |
int LEFT = 1; | |
int MIDDLE = 2; | |
int RIGHT = 3; | |
AprilTagDetection tagOfInterest = null; | |
@Override | |
public void runOpMode() | |
{ | |
int cameraMonitorViewId = hardwareMap.appContext.getResources().getIdentifier("cameraMonitorViewId", "id", hardwareMap.appContext.getPackageName()); | |
camera = OpenCvCameraFactory.getInstance().createWebcam(hardwareMap.get(WebcamName.class, "Webcam 1"), cameraMonitorViewId); | |
aprilTagDetectionPipeline = new AprilTagDetectionPipeline(tagsize, fx, fy, cx, cy); | |
camera.setPipeline(aprilTagDetectionPipeline); | |
camera.openCameraDeviceAsync(new OpenCvCamera.AsyncCameraOpenListener() | |
{ | |
@Override | |
public void onOpened() | |
{ | |
camera.startStreaming(800,448, OpenCvCameraRotation.UPRIGHT); | |
} | |
@Override | |
public void onError(int errorCode) | |
{ | |
} | |
}); | |
telemetry.setMsTransmissionInterval(50); | |
/* | |
* The INIT-loop: | |
* This REPLACES waitForStart! | |
*/ | |
while (!isStarted() && !isStopRequested()) | |
{ | |
ArrayList<AprilTagDetection> currentDetections = aprilTagDetectionPipeline.getLatestDetections(); | |
if(currentDetections.size() != 0) | |
{ | |
boolean tagFound = false; | |
for(AprilTagDetection tag : currentDetections) | |
{ | |
if(tag.id == LEFT || tag.id == MIDDLE || tag.id == RIGHT) | |
{ | |
tagOfInterest = tag; | |
tagFound = true; | |
break; | |
} | |
} | |
if(tagFound) | |
{ | |
telemetry.addLine("Tag of interest is in sight!\n\nLocation data:"); | |
tagToTelemetry(tagOfInterest); | |
} | |
else | |
{ | |
telemetry.addLine("Don't see tag of interest :("); | |
if(tagOfInterest == null) | |
{ | |
telemetry.addLine("(The tag has never been seen)"); | |
} | |
else | |
{ | |
telemetry.addLine("\nBut we HAVE seen the tag before; last seen at:"); | |
tagToTelemetry(tagOfInterest); | |
} | |
} | |
} | |
else | |
{ | |
telemetry.addLine("Don't see tag of interest :("); | |
if(tagOfInterest == null) | |
{ | |
telemetry.addLine("(The tag has never been seen)"); | |
} | |
else | |
{ | |
telemetry.addLine("\nBut we HAVE seen the tag before; last seen at:"); | |
tagToTelemetry(tagOfInterest); | |
} | |
} | |
telemetry.update(); | |
sleep(20); | |
} | |
/* | |
* The START command just came in: now work off the latest snapshot acquired | |
* during the init loop. | |
*/ | |
/* Update the telemetry */ | |
if(tagOfInterest != null) | |
{ | |
telemetry.addLine("Tag snapshot:\n"); | |
tagToTelemetry(tagOfInterest); | |
telemetry.update(); | |
} | |
else | |
{ | |
telemetry.addLine("No tag snapshot available, it was never sighted during the init loop :("); | |
telemetry.update(); | |
} | |
/* Actually do something useful */ | |
if(tagOfInterest == null){ | |
//default trajectory here if preferred | |
}else if(tagOfInterest.id == LEFT){ | |
//left trajectory | |
}else if(tagOfInterest.id == MIDDLE){ | |
//middle trajectory | |
}else{ | |
//right trajectory | |
} | |
/* You wouldn't have this in your autonomous, this is just to prevent the sample from ending */ | |
while (opModeIsActive()) {sleep(20);} | |
} | |
void tagToTelemetry(AprilTagDetection detection) | |
{ | |
telemetry.addLine(String.format("\nDetected tag ID=%d", detection.id)); | |
telemetry.addLine(String.format("Translation X: %.2f feet", detection.pose.x*FEET_PER_METER)); | |
telemetry.addLine(String.format("Translation Y: %.2f feet", detection.pose.y*FEET_PER_METER)); | |
telemetry.addLine(String.format("Translation Z: %.2f feet", detection.pose.z*FEET_PER_METER)); | |
telemetry.addLine(String.format("Rotation Yaw: %.2f degrees", Math.toDegrees(detection.pose.yaw))); | |
telemetry.addLine(String.format("Rotation Pitch: %.2f degrees", Math.toDegrees(detection.pose.pitch))); | |
telemetry.addLine(String.format("Rotation Roll: %.2f degrees", Math.toDegrees(detection.pose.roll))); | |
} | |
} |