Skip to content

Commit

Permalink
Merge pull request #21 from GreenBlitz/vision
Browse files Browse the repository at this point in the history
Vision
  • Loading branch information
GilStein1 authored Jun 19, 2024
2 parents b7d29ed + 434c422 commit c8ed46c
Show file tree
Hide file tree
Showing 16 changed files with 311 additions and 13 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package org.firstinspires.ftc.teamcode;

public enum Alliance {

BLUE,
RED

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package org.firstinspires.ftc.teamcode;

public enum Location {

LEFT,
CENTER,
RIGHT

}
42 changes: 29 additions & 13 deletions TeamCode/src/main/java/org/firstinspires/ftc/teamcode/Robot.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

import com.arcrobotics.ftclib.command.SequentialCommandGroup;
import com.qualcomm.robotcore.hardware.HardwareMap;

import org.firstinspires.ftc.teamcode.subsystems.arm.Arm;
import org.firstinspires.ftc.teamcode.subsystems.vision.Vision;
import org.firstinspires.ftc.teamcode.subsystems.claw.Claw;
import org.firstinspires.ftc.teamcode.subsystems.elevator.Elevator;
import org.firstinspires.ftc.teamcode.subsystems.wrist.Wrist;
Expand All @@ -25,26 +25,34 @@ public static Robot getInstance() {
return instance;
}


private Alliance alliance;
private RobotState currentState;
private Arm arm;
private MecanumChassis chassis;
private Claw claw;
private Elevator elevator;
private Launcher launcher;
private Vision vision;
private Wrist wrist;

private void initSubsystems(HardwareMap hardwareMap) {
// if (currentState == null) {
this.currentState = RobotState.DRIVE;

this.arm = new Arm(hardwareMap);
this.chassis = new MecanumChassis(hardwareMap);
this.claw = new Claw(hardwareMap);
this.elevator = new Elevator(hardwareMap);
this.launcher = new Launcher(hardwareMap);
this.wrist = new Wrist(hardwareMap);
// }
private Robot() {
this.alliance = Alliance.RED;
}

public void setAlliance(Alliance alliance) {
this.alliance = alliance;
}

public void initSubsystems(HardwareMap hardwareMap) {
this.currentState = RobotState.DRIVE;

this.arm = new Arm(hardwareMap);
this.chassis = new MecanumChassis(hardwareMap);
this.claw = new Claw(hardwareMap);
this.elevator = new Elevator(hardwareMap);
this.launcher = new Launcher(hardwareMap);
this.vision = new Vision(hardwareMap);
this.wrist = new Wrist(hardwareMap);
}

public SequentialCommandGroup setState(RobotState robotState) {
Expand All @@ -66,6 +74,10 @@ public RobotState getCurrentState() {
return currentState;
}

public Alliance getAlliance() {
return alliance;
}

public Arm getArm() {
return arm;
}
Expand All @@ -86,6 +98,10 @@ public Launcher getLauncher() {
return launcher;
}

public Vision getVision() {
return vision;
}

public Wrist getWrist() {
return wrist;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package org.firstinspires.ftc.teamcode.autos;

import com.qualcomm.robotcore.eventloop.opmode.LinearOpMode;

import org.firstinspires.ftc.teamcode.Alliance;
import org.firstinspires.ftc.teamcode.Robot;

public abstract class DefaultGil extends LinearOpMode {

@Override
public void runOpMode() throws InterruptedException {
Robot.getInstance().setAlliance(setAlliance());
run();
}

public abstract Alliance setAlliance();
public abstract void run() throws InterruptedException;

}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.arcrobotics.ftclib.command.CommandScheduler;
import com.qualcomm.robotcore.eventloop.opmode.OpMode;

import org.firstinspires.ftc.teamcode.Alliance;
import org.firstinspires.ftc.teamcode.Robot;

public abstract class DefaultRaz extends OpMode {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import com.qualcomm.robotcore.eventloop.opmode.TeleOp;

import org.firstinspires.ftc.teamcode.Alliance;
import org.firstinspires.ftc.teamcode.Bindings;
import org.firstinspires.ftc.teamcode.Robot;
import org.firstinspires.ftc.teamcode.opmodes.DefaultRaz;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.qualcomm.robotcore.eventloop.opmode.TeleOp;

import org.firstinspires.ftc.teamcode.Alliance;
import org.firstinspires.ftc.teamcode.Bindings;
import org.firstinspires.ftc.teamcode.Robot;
import org.firstinspires.ftc.teamcode.opmodes.DefaultRaz;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.qualcomm.robotcore.eventloop.opmode.TeleOp;

import org.firstinspires.ftc.teamcode.Alliance;
import org.firstinspires.ftc.teamcode.Bindings;
import org.firstinspires.ftc.teamcode.Robot;
import org.firstinspires.ftc.teamcode.opmodes.DefaultRaz;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.qualcomm.robotcore.eventloop.opmode.TeleOp;

import org.firstinspires.ftc.teamcode.Alliance;
import org.firstinspires.ftc.teamcode.Bindings;
import org.firstinspires.ftc.teamcode.Robot;
import org.firstinspires.ftc.teamcode.opmodes.DefaultRaz;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.qualcomm.robotcore.eventloop.opmode.TeleOp;

import org.firstinspires.ftc.teamcode.Alliance;
import org.firstinspires.ftc.teamcode.Bindings;
import org.firstinspires.ftc.teamcode.Robot;
import org.firstinspires.ftc.teamcode.opmodes.DefaultRaz;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.firstinspires.ftc.teamcode.opmodes.subsystemstesters;

import org.firstinspires.ftc.teamcode.Alliance;
import org.firstinspires.ftc.teamcode.Bindings;
import org.firstinspires.ftc.teamcode.Robot;
import org.firstinspires.ftc.teamcode.opmodes.DefaultRaz;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package org.firstinspires.ftc.teamcode.opmodes.subsystemstesters;

import com.qualcomm.robotcore.eventloop.opmode.TeleOp;

import org.firstinspires.ftc.teamcode.Alliance;
import org.firstinspires.ftc.teamcode.Robot;
import org.firstinspires.ftc.teamcode.opmodes.DefaultRaz;

@TeleOp(name = "Raz Vision Test")
public class RazVisionTest extends DefaultRaz {

@Override
public void initialize() {

}

@Override
public void execute() {
Robot.getInstance().getVision().telemetry(telemetry);
}

@Override
public void configureBindings() {

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.qualcomm.robotcore.eventloop.opmode.TeleOp;

import org.firstinspires.ftc.teamcode.Alliance;
import org.firstinspires.ftc.teamcode.Bindings;
import org.firstinspires.ftc.teamcode.Robot;
import org.firstinspires.ftc.teamcode.opmodes.DefaultRaz;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package org.firstinspires.ftc.teamcode.subsystems.vision;

import android.graphics.Canvas;
import org.firstinspires.ftc.robotcore.internal.camera.calibration.CameraCalibration;
import org.firstinspires.ftc.teamcode.Alliance;
import org.firstinspires.ftc.teamcode.Location;
import org.firstinspires.ftc.teamcode.Robot;
import org.firstinspires.ftc.vision.VisionProcessor;
import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.Rect;
import org.opencv.core.Scalar;
import org.opencv.imgproc.Imgproc;

public class PropProcessor implements VisionProcessor {

private Location location;

@Override
public void init(int width, int height, CameraCalibration calibration) {

}

@Override
public Object processFrame(Mat frame, long captureTimeNanos) {
Mat leftZone = getLeftZoneMatrix(frame);
Mat centerZone = getCenterZoneMatrix(frame);

Scalar left = getAvgColor(leftZone);
Scalar center = getAvgColor(centerZone);

if (isPropPartOfAvgColor(left)) {
this.location = Location.LEFT;
}
else if (isPropPartOfAvgColor(center)) {
this.location = Location.CENTER;
}
else {
this.location = Location.RIGHT;
}

leftZone.release();
centerZone.release();

return null;
}

public Mat getLeftZoneMatrix(Mat frame) {
if (Robot.getInstance().getAlliance() == Alliance.RED) {
return frame.submat(VisionConstant.RED_LEFT_ZONE_AREA);
}
else {
return frame.submat(VisionConstant.BLUE_LEFT_ZONE_AREA);
}
}

public Mat getCenterZoneMatrix(Mat frame) {
if (Robot.getInstance().getAlliance() == Alliance.RED) {
return frame.submat(VisionConstant.RED_CENTER_ZONE_AREA);
}
else {
return frame.submat(VisionConstant.BLUE_CENTER_ZONE_AREA);
}
}

public Scalar getAvgColor(Mat matrix) {
Imgproc.blur(matrix, matrix, VisionConstant.BLUR_SIZE);
return Core.mean(matrix);
}

public double getAllianceColorThreshold() {
return Robot.getInstance().getAlliance() == Alliance.RED ? VisionConstant.RED_THRESHOLD : VisionConstant.BLUE_THRESHOLD;
}

public boolean isPropPartOfAvgColor(Scalar color) {
int allianceColorIndex = Robot.getInstance().getAlliance() == Alliance.RED ? VisionConstant.RED_INDEX : VisionConstant.BLUE_INDEX;
double allianceColor = color.val[allianceColorIndex];
boolean allianceColorPassesThreshold = allianceColor > getAllianceColorThreshold();
double sumOfColor = color.val[VisionConstant.RED_INDEX] + color.val[VisionConstant.GREEN_INDEX] + color.val[VisionConstant.BLUE_INDEX];
return allianceColorPassesThreshold && sumOfColor < VisionConstant.AMOUNT_OF_COLOR * allianceColor;
}

@Override
public void onDrawFrame(Canvas canvas, int onscreenWidth, int onscreenHeight, float scaleBmpPxToCanvasPx, float scaleCanvasDensity, Object userContext) {

}

public Location getLocation() {
return location;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package org.firstinspires.ftc.teamcode.subsystems.vision;

import android.util.Pair;
import android.util.Size;
import com.arcrobotics.ftclib.command.SubsystemBase;
import com.qualcomm.robotcore.hardware.HardwareMap;
import org.firstinspires.ftc.robotcore.external.Telemetry;
import org.firstinspires.ftc.robotcore.external.hardware.camera.WebcamName;
import org.firstinspires.ftc.teamcode.Location;
import org.firstinspires.ftc.vision.VisionPortal;
import org.firstinspires.ftc.vision.apriltag.AprilTagDetection;
import org.firstinspires.ftc.vision.apriltag.AprilTagPoseFtc;
import org.firstinspires.ftc.vision.apriltag.AprilTagProcessor;
import org.firstinspires.ftc.vision.tfod.TfodProcessor;
import java.util.ArrayList;
import java.util.List;

public class Vision extends SubsystemBase {

private final AprilTagProcessor aprilTagProcessor;
private final TfodProcessor tfodProcessor;
private final PropProcessor propProcessor;
private final VisionPortal visionPortal;

public Vision(HardwareMap hardwareMap) {
this.aprilTagProcessor = new AprilTagProcessor.Builder()
.setDrawTagID(true)
.setDrawTagOutline(true)
.setDrawAxes(true)
.setDrawCubeProjection(true)
.build();

this.tfodProcessor = new TfodProcessor.Builder()
.setMaxNumRecognitions(VisionConstant.MAX_NUM_RECOGNITIONS)
.setUseObjectTracker(true)
.setTrackerMaxOverlap(VisionConstant.TRACKER_MAX_OVERLAP)
.setTrackerMinSize(VisionConstant.TRACKER_MIN_SIZE)
.build();

propProcessor = new PropProcessor();

this.visionPortal = new VisionPortal.Builder()
.setCamera(hardwareMap.get(WebcamName.class, VisionConstant.CAMERA_ID))
.addProcessors(aprilTagProcessor, tfodProcessor, propProcessor)
.setCameraResolution(new Size(VisionConstant.CAMERA_RESOLUTION_WIDTH, VisionConstant.CAMERA_RESOLUTION_HEIGHT))
.setStreamFormat(VisionConstant.STREAM_FORMAT)
.enableLiveView(true)
.setAutoStopLiveView(true)
.build();
}

public List<AprilTagDetection> getTagsDetections() {
return aprilTagProcessor.getDetections();
}

public List<Pair<AprilTagPoseFtc,Integer>> getRelativeTagsPoses() {
List<AprilTagDetection> temp = getTagsDetections();
List<Pair<AprilTagPoseFtc,Integer>> poses = new ArrayList<>();
for(AprilTagDetection detection : temp) {
if (detection.metadata != null) {
poses.add(new Pair<>(detection.ftcPose, detection.id));
}
}
return poses;
}

public void telemetry(Telemetry telemetry) {
List<Pair<AprilTagPoseFtc,Integer>> poses = getRelativeTagsPoses();
if(!poses.isEmpty()) {
telemetry.addData("detected: ", poses.size() + " AprilTags");
telemetry.addData("the first tag is: ", poses.get(0).second);
telemetry.addData("first tag x: ", poses.get(0).first.x);
telemetry.addData("first tag y: ", poses.get(0).first.y);
telemetry.addData("first tag z: ", poses.get(0).first.z);
}
Location propLocation = propProcessor.getLocation();

if(propLocation != null) {
telemetry.addData("prop's location is: ", propLocation.toString());
}
}

}
Loading

0 comments on commit c8ed46c

Please sign in to comment.