Compare commits
18 Commits
SpindexerP
...
c2e9d8fa87
| Author | SHA1 | Date | |
|---|---|---|---|
| c2e9d8fa87 | |||
| 46a5366a4a | |||
|
|
298b7bca8c | ||
| 2f0fcad128 | |||
| 45199b952b | |||
| 76ceb91fb7 | |||
| daccec4fdd | |||
| b55d44ae97 | |||
| 50212015e3 | |||
| c271c88e45 | |||
| 33300876ef | |||
| e1745500cc | |||
| 0dbf155608 | |||
| 313eeeaa95 | |||
| b28647373a | |||
| 7e7254aaea | |||
| a3068cea2e | |||
| f1d4bb9d24 |
@@ -710,7 +710,7 @@ public class ProtoAutoClose_V3 extends LinearOpMode {
|
|||||||
bearing = result.getTx();
|
bearing = result.getTx();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
double turretPos = robot.turr1Pos.getCurrentPosition() - (bearing / 1300);
|
double turretPos = (bearing / 1300);
|
||||||
robot.turr1.setPosition(turretPos);
|
robot.turr1.setPosition(turretPos);
|
||||||
robot.turr2.setPosition(1 - turretPos);
|
robot.turr2.setPosition(1 - turretPos);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,4 +42,8 @@ public class ServoPositions {
|
|||||||
public static double turret_detectBlueClose = 0.6;
|
public static double turret_detectBlueClose = 0.6;
|
||||||
public static double turrDefault = 0.4;
|
public static double turrDefault = 0.4;
|
||||||
|
|
||||||
|
public static double turrMin = 0.2;
|
||||||
|
public static double turrMax = 0.8;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ import org.firstinspires.ftc.teamcode.utils.Flywheel;
|
|||||||
import org.firstinspires.ftc.teamcode.utils.Robot;
|
import org.firstinspires.ftc.teamcode.utils.Robot;
|
||||||
import org.firstinspires.ftc.teamcode.utils.Servos;
|
import org.firstinspires.ftc.teamcode.utils.Servos;
|
||||||
import org.firstinspires.ftc.teamcode.utils.Spindexer;
|
import org.firstinspires.ftc.teamcode.utils.Spindexer;
|
||||||
|
import org.firstinspires.ftc.teamcode.utils.Targeting;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -49,10 +50,14 @@ public class TeleopV3 extends LinearOpMode {
|
|||||||
public static double spindexPos = spindexer_intakePos1;
|
public static double spindexPos = spindexer_intakePos1;
|
||||||
public static double spinPow = 0.09;
|
public static double spinPow = 0.09;
|
||||||
public static double bMult = 1, bDiv = 2200;
|
public static double bMult = 1, bDiv = 2200;
|
||||||
|
public static double limelightKp = 0.001; // Proportional gain for limelight auto-aim
|
||||||
|
public static double limelightDeadband = 0.5; // Ignore tx values smaller than this
|
||||||
public static double tp = 0.8, ti = 0.001, td = 0.0315, tf = 0;
|
public static double tp = 0.8, ti = 0.001, td = 0.0315, tf = 0;
|
||||||
public static boolean manualTurret = true;
|
public static boolean manualTurret = true;
|
||||||
public double vel = 3000;
|
public double vel = 3000;
|
||||||
public boolean autoVel = true;
|
public boolean autoVel = true;
|
||||||
|
public boolean targetingVel = true;
|
||||||
|
public boolean targetingHood = true;
|
||||||
public double manualOffset = 0.0;
|
public double manualOffset = 0.0;
|
||||||
public boolean autoHood = true;
|
public boolean autoHood = true;
|
||||||
public boolean green1 = false;
|
public boolean green1 = false;
|
||||||
@@ -72,6 +77,8 @@ public class TeleopV3 extends LinearOpMode {
|
|||||||
Flywheel flywheel;
|
Flywheel flywheel;
|
||||||
MecanumDrive drive;
|
MecanumDrive drive;
|
||||||
Spindexer spindexer;
|
Spindexer spindexer;
|
||||||
|
Targeting targeting;
|
||||||
|
Targeting.Settings targetingSettings;
|
||||||
double autoHoodOffset = 0.0;
|
double autoHoodOffset = 0.0;
|
||||||
|
|
||||||
int shooterTicker = 0;
|
int shooterTicker = 0;
|
||||||
@@ -116,6 +123,7 @@ public class TeleopV3 extends LinearOpMode {
|
|||||||
private double transferStamp = 0.0;
|
private double transferStamp = 0.0;
|
||||||
private int tickerA = 1;
|
private int tickerA = 1;
|
||||||
private boolean transferIn = false;
|
private boolean transferIn = false;
|
||||||
|
boolean turretInterpolate = true;
|
||||||
|
|
||||||
public static double velPrediction(double distance) {
|
public static double velPrediction(double distance) {
|
||||||
if (distance < 30) {
|
if (distance < 30) {
|
||||||
@@ -146,18 +154,20 @@ public class TeleopV3 extends LinearOpMode {
|
|||||||
flywheel = new Flywheel(hardwareMap);
|
flywheel = new Flywheel(hardwareMap);
|
||||||
drive = new MecanumDrive(hardwareMap, teleStart);
|
drive = new MecanumDrive(hardwareMap, teleStart);
|
||||||
spindexer = new Spindexer(hardwareMap);
|
spindexer = new Spindexer(hardwareMap);
|
||||||
|
targeting = new Targeting();
|
||||||
|
targetingSettings = new Targeting.Settings(0.0,0.0);
|
||||||
|
|
||||||
PIDFController tController = new PIDFController(tp, ti, td, tf);
|
PIDFController tController = new PIDFController(tp, ti, td, tf);
|
||||||
|
|
||||||
tController.setTolerance(0.001);
|
tController.setTolerance(0.001);
|
||||||
|
//
|
||||||
|
// if (redAlliance) {
|
||||||
|
// robot.limelight.pipelineSwitch(3);
|
||||||
|
// } else {
|
||||||
|
// robot.limelight.pipelineSwitch(2);
|
||||||
|
// }
|
||||||
|
|
||||||
if (redAlliance) {
|
// robot.limelight.start();
|
||||||
robot.limelight.pipelineSwitch(3);
|
|
||||||
} else {
|
|
||||||
robot.limelight.pipelineSwitch(2);
|
|
||||||
}
|
|
||||||
|
|
||||||
robot.limelight.start();
|
|
||||||
|
|
||||||
waitForStart();
|
waitForStart();
|
||||||
if (isStopRequested()) return;
|
if (isStopRequested()) return;
|
||||||
@@ -402,13 +412,14 @@ public class TeleopV3 extends LinearOpMode {
|
|||||||
pos = 0.83;
|
pos = 0.83;
|
||||||
}
|
}
|
||||||
|
|
||||||
//SHOOTER:
|
|
||||||
|
|
||||||
flywheel.manageFlywheel(vel);
|
targetingSettings = targeting.calculateSettings
|
||||||
|
(robotX,robotY,robotHeading,0.0, turretInterpolate);
|
||||||
|
|
||||||
//VELOCITY AUTOMATIC
|
//VELOCITY AUTOMATIC
|
||||||
|
if (targetingVel) {
|
||||||
if (autoVel) {
|
vel = targetingSettings.flywheelRPM;
|
||||||
|
} else if (autoVel) {
|
||||||
vel = velPrediction(distanceToGoal);
|
vel = velPrediction(distanceToGoal);
|
||||||
} else {
|
} else {
|
||||||
vel = manualVel;
|
vel = manualVel;
|
||||||
@@ -430,48 +441,105 @@ public class TeleopV3 extends LinearOpMode {
|
|||||||
manualVel = 3100;
|
manualVel = 3100;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//SHOOTER:
|
||||||
|
flywheel.manageFlywheel(vel);
|
||||||
|
|
||||||
//TODO: test the camera teleop code
|
//TODO: test the camera teleop code
|
||||||
|
|
||||||
|
// TODO: TEST THIS CODE
|
||||||
|
|
||||||
TELE.addData("posS2", pos);
|
TELE.addData("posS2", pos);
|
||||||
|
|
||||||
if (y < 0.3 && y > -0.3 && x < 0.3 && x > -0.3 && rx < 0.3 && rx > -0.3) { //not moving
|
|
||||||
double bearing;
|
|
||||||
|
|
||||||
LLResult result = robot.limelight.getLatestResult();
|
LLResult result = robot.limelight.getLatestResult();
|
||||||
if (result != null) {
|
boolean limelightActive = false;
|
||||||
if (result.isValid()) {
|
|
||||||
bearing = result.getTx() * bMult;
|
|
||||||
|
|
||||||
double bearingCorrection = bearing / bDiv;
|
double turretMin = 0.13;
|
||||||
|
double turretMax = 0.83;
|
||||||
|
|
||||||
error += bearingCorrection;
|
if (result != null && result.isValid()) {
|
||||||
|
double tx = result.getTx();
|
||||||
|
double ty = result.getTy();
|
||||||
|
|
||||||
|
if (Math.abs(tx) > limelightDeadband) {
|
||||||
|
limelightActive = true;
|
||||||
|
overrideTurr = true;
|
||||||
|
|
||||||
|
double currentTurretPos = servo.getTurrPos();
|
||||||
|
|
||||||
|
// + tx means tag is right, so rotate right
|
||||||
|
double adjustment = -tx * limelightKp;
|
||||||
|
|
||||||
|
// calculate new position
|
||||||
|
double newTurretPos = currentTurretPos + adjustment;
|
||||||
|
|
||||||
|
if (newTurretPos < turretMin) {
|
||||||
|
double forwardDist = turretMin - newTurretPos;
|
||||||
|
double backwardDist = (currentTurretPos - turretMin) + (turretMax - newTurretPos);
|
||||||
|
// check path distance
|
||||||
|
if (backwardDist < forwardDist && backwardDist < (turretMax - turretMin) / 2) {
|
||||||
|
newTurretPos = turretMax - (turretMin - newTurretPos);
|
||||||
|
} else {
|
||||||
|
newTurretPos = turretMin;
|
||||||
|
}
|
||||||
|
} else if (newTurretPos > turretMax) {
|
||||||
|
double forwardDist = newTurretPos - turretMax;
|
||||||
|
double backwardDist = (turretMax - currentTurretPos) + (newTurretPos - turretMin);
|
||||||
|
if (backwardDist < forwardDist && backwardDist < (turretMax - turretMin) / 2) {
|
||||||
|
newTurretPos = turretMin + (newTurretPos - turretMax);
|
||||||
|
} else {
|
||||||
|
newTurretPos = turretMax;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Final clamp
|
||||||
|
if (newTurretPos < turretMin) {
|
||||||
|
newTurretPos = turretMin;
|
||||||
|
} else if (newTurretPos > turretMax) {
|
||||||
|
newTurretPos = turretMax;
|
||||||
|
}
|
||||||
|
|
||||||
|
pos = newTurretPos;
|
||||||
|
turretPos = pos;
|
||||||
|
|
||||||
camTicker++;
|
camTicker++;
|
||||||
TELE.addData("tx", bearingCorrection);
|
TELE.addData("tx", tx);
|
||||||
TELE.addData("ty", result.getTy());
|
TELE.addData("ty", ty);
|
||||||
|
TELE.addData("limelightAdjustment", adjustment);
|
||||||
|
TELE.addData("limelightActive", true);
|
||||||
|
} else {
|
||||||
|
limelightActive = true;
|
||||||
|
overrideTurr = true;
|
||||||
|
TELE.addData("tx", tx);
|
||||||
|
TELE.addData("ty", ty);
|
||||||
|
TELE.addData("limelightActive", true);
|
||||||
|
TELE.addData("limelightStatus", "Centered");
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
|
if (y < 0.3 && y > -0.3 && x < 0.3 && x > -0.3 && rx < 0.3 && rx > -0.3) {
|
||||||
|
TELE.addData("limelightActive", false);
|
||||||
|
TELE.addData("limelightStatus", "No target");
|
||||||
} else {
|
} else {
|
||||||
camTicker = 0;
|
camTicker = 0;
|
||||||
overrideTurr = false;
|
overrideTurr = false;
|
||||||
|
limelightActive = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!overrideTurr) {
|
if (!limelightActive && !overrideTurr) {
|
||||||
turretPos = pos;
|
turretPos = pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
TELE.addData("posS3", turretPos);
|
TELE.addData("posS3", turretPos);
|
||||||
|
|
||||||
if (manualTurret) {
|
if (manualTurret && !limelightActive) {
|
||||||
pos = turrDefault + (manualOffset / 100) + error;
|
pos = turrDefault + (manualOffset / 100) + error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!overrideTurr) {
|
if (!overrideTurr && !limelightActive) {
|
||||||
turretPos = pos;
|
turretPos = pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Math.abs(gamepad2.left_stick_x)>0.2) {
|
if (Math.abs(gamepad2.left_stick_x)>0.2 && !limelightActive) {
|
||||||
manualOffset += 1.35 * gamepad2.left_stick_x;
|
manualOffset += 1.35 * gamepad2.left_stick_x;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -480,7 +548,9 @@ public class TeleopV3 extends LinearOpMode {
|
|||||||
|
|
||||||
//HOOD:
|
//HOOD:
|
||||||
|
|
||||||
if (autoHood) {
|
if (targetingHood) {
|
||||||
|
robot.hood.setPosition(targetingSettings.hoodAngle);
|
||||||
|
} else if (autoHood) {
|
||||||
robot.hood.setPosition(0.15 + hoodOffset);
|
robot.hood.setPosition(0.15 + hoodOffset);
|
||||||
} else {
|
} else {
|
||||||
robot.hood.setPosition(hoodDefaultPos + hoodOffset);
|
robot.hood.setPosition(hoodDefaultPos + hoodOffset);
|
||||||
@@ -845,16 +915,28 @@ public class TeleopV3 extends LinearOpMode {
|
|||||||
TELE.addData("shootOrder", shootOrder);
|
TELE.addData("shootOrder", shootOrder);
|
||||||
TELE.addData("oddColor", oddBallColor);
|
TELE.addData("oddColor", oddBallColor);
|
||||||
|
|
||||||
|
// Spindexer Debug
|
||||||
TELE.addData("spinEqual", servo.spinEqual(spindexer_intakePos1));
|
TELE.addData("spinEqual", servo.spinEqual(spindexer_intakePos1));
|
||||||
TELE.addData("spinCommmandedPos", spindexer.commandedIntakePosition);
|
TELE.addData("spinCommmandedPos", spindexer.commandedIntakePosition);
|
||||||
TELE.addData("spinIntakeState", spindexer.currentIntakeState);
|
TELE.addData("spinIntakeState", spindexer.currentIntakeState);
|
||||||
TELE.addData("spinTestCounter", spindexer.counter);
|
TELE.addData("spinTestCounter", spindexer.counter);
|
||||||
TELE.addData("autoSpintake", autoSpintake);
|
TELE.addData("autoSpintake", autoSpintake);
|
||||||
TELE.addData("distanceRearCenter", spindexer.distanceRearCenter);
|
//TELE.addData("distanceRearCenter", spindexer.distanceRearCenter);
|
||||||
TELE.addData("distanceFrontDriver", spindexer.distanceFrontDriver);
|
//TELE.addData("distanceFrontDriver", spindexer.distanceFrontDriver);
|
||||||
TELE.addData("distanceFrontPassenger", spindexer.distanceFrontPassenger);
|
//TELE.addData("distanceFrontPassenger", spindexer.distanceFrontPassenger);
|
||||||
TELE.addData("shootall commanded", shootAll);
|
TELE.addData("shootall commanded", shootAll);
|
||||||
|
// Targeting Debug
|
||||||
|
TELE.addData("robotX", robotX);
|
||||||
|
TELE.addData( "robotY", robotY);
|
||||||
|
TELE.addData("robotInchesX", targeting.robotInchesX);
|
||||||
|
TELE.addData( "robotInchesY", targeting.robotInchesY);
|
||||||
|
TELE.addData("Targeting Interpolate", turretInterpolate);
|
||||||
|
TELE.addData("Targeting GridX", targeting.robotGridX);
|
||||||
|
TELE.addData("Targeting GridY", targeting.robotGridY);
|
||||||
|
TELE.addData("Targeting FlyWheel", targetingSettings.flywheelRPM);
|
||||||
|
TELE.addData("Targeting HoodAngle", targetingSettings.hoodAngle);
|
||||||
TELE.addData("timeSinceStamp", getRuntime() - shootStamp);
|
TELE.addData("timeSinceStamp", getRuntime() - shootStamp);
|
||||||
|
|
||||||
TELE.update();
|
TELE.update();
|
||||||
|
|
||||||
ticker++;
|
ticker++;
|
||||||
|
|||||||
@@ -52,7 +52,6 @@ public class PIDServoTest extends LinearOpMode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
telemetry.addData("pos", pos);
|
telemetry.addData("pos", pos);
|
||||||
telemetry.addData("Turret Voltage", robot.turr1Pos.getCurrentPosition());
|
|
||||||
telemetry.addData("Spindex Voltage", robot.spin1Pos.getVoltage());
|
telemetry.addData("Spindex Voltage", robot.spin1Pos.getVoltage());
|
||||||
telemetry.addData("target", target);
|
telemetry.addData("target", target);
|
||||||
telemetry.addData("Mode", mode);
|
telemetry.addData("Mode", mode);
|
||||||
|
|||||||
@@ -0,0 +1,67 @@
|
|||||||
|
package org.firstinspires.ftc.teamcode.tests;
|
||||||
|
|
||||||
|
import static org.firstinspires.ftc.teamcode.constants.Poses.goalPose;
|
||||||
|
|
||||||
|
import com.acmerobotics.dashboard.FtcDashboard;
|
||||||
|
import com.acmerobotics.dashboard.config.Config;
|
||||||
|
import com.acmerobotics.dashboard.telemetry.MultipleTelemetry;
|
||||||
|
import com.acmerobotics.roadrunner.Pose2d;
|
||||||
|
import com.acmerobotics.roadrunner.Vector2d;
|
||||||
|
import com.qualcomm.robotcore.eventloop.opmode.Autonomous;
|
||||||
|
import com.qualcomm.robotcore.eventloop.opmode.LinearOpMode;
|
||||||
|
|
||||||
|
import org.firstinspires.ftc.teamcode.libs.RR.MecanumDrive;
|
||||||
|
import org.firstinspires.ftc.teamcode.utils.AprilTagWebcam;
|
||||||
|
import org.firstinspires.ftc.teamcode.utils.Robot;
|
||||||
|
import org.firstinspires.ftc.teamcode.utils.Turret;
|
||||||
|
import org.firstinspires.ftc.vision.apriltag.AprilTagDetection;
|
||||||
|
|
||||||
|
@Autonomous
|
||||||
|
@Config
|
||||||
|
public class TurretTest extends LinearOpMode {
|
||||||
|
@Override
|
||||||
|
public void runOpMode() throws InterruptedException {
|
||||||
|
|
||||||
|
Robot robot = new Robot(hardwareMap);
|
||||||
|
MultipleTelemetry TELE = new MultipleTelemetry(
|
||||||
|
telemetry, FtcDashboard.getInstance().getTelemetry()
|
||||||
|
);
|
||||||
|
|
||||||
|
AprilTagWebcam webcam = new AprilTagWebcam();
|
||||||
|
webcam.init(robot, TELE);
|
||||||
|
|
||||||
|
Turret turret = new Turret(robot, TELE, webcam);
|
||||||
|
waitForStart();
|
||||||
|
|
||||||
|
MecanumDrive drive = new MecanumDrive(hardwareMap, new Pose2d(10, 0,0));
|
||||||
|
|
||||||
|
while(opModeIsActive()){
|
||||||
|
|
||||||
|
drive.updatePoseEstimate();
|
||||||
|
Pose2d robotPose = drive.localizer.getPose();
|
||||||
|
|
||||||
|
double dx = goalPose.position.x - robotPose.position.x;
|
||||||
|
double dy = goalPose.position.y - robotPose.position.y;
|
||||||
|
|
||||||
|
double heading = robotPose.heading.toDouble();
|
||||||
|
|
||||||
|
// field vector -> robot frame... avoids double calculation
|
||||||
|
double relX = dx * Math.cos(-heading) - dy * Math.sin(-heading);
|
||||||
|
double relY = dx * Math.sin(-heading) + dy * Math.cos(-heading);
|
||||||
|
|
||||||
|
Pose2d deltaPos = new Pose2d(
|
||||||
|
new Vector2d(relX, relY),
|
||||||
|
robotPose.heading
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
turret.trackGoal(deltaPos);
|
||||||
|
|
||||||
|
TELE.addData("Robot Pose", robotPose);
|
||||||
|
TELE.addData("Goal Pose", goalPose);
|
||||||
|
TELE.addData("Delta Pos", deltaPos);
|
||||||
|
TELE.update();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,22 +1,13 @@
|
|||||||
package org.firstinspires.ftc.teamcode.utils;
|
package org.firstinspires.ftc.teamcode.utils;
|
||||||
|
|
||||||
import static org.firstinspires.ftc.teamcode.constants.ShooterVars.kP;
|
|
||||||
import static org.firstinspires.ftc.teamcode.constants.ShooterVars.maxStep;
|
|
||||||
import com.arcrobotics.ftclib.controller.PIDFController;
|
|
||||||
import com.qualcomm.robotcore.hardware.DcMotor;
|
import com.qualcomm.robotcore.hardware.DcMotor;
|
||||||
import com.qualcomm.robotcore.hardware.HardwareMap;
|
import com.qualcomm.robotcore.hardware.HardwareMap;
|
||||||
|
|
||||||
import com.acmerobotics.dashboard.telemetry.MultipleTelemetry;
|
import com.qualcomm.robotcore.hardware.PIDFCoefficients;
|
||||||
|
|
||||||
public class Flywheel {
|
public class Flywheel {
|
||||||
Robot robot;
|
Robot robot;
|
||||||
MultipleTelemetry TELE;
|
public PIDFCoefficients shooterPIDF1, shooterPIDF2;
|
||||||
|
|
||||||
double initPos = 0.0;
|
|
||||||
double stamp = 0.0;
|
|
||||||
double stamp1 = 0.0;
|
|
||||||
double ticker = 0.0;
|
|
||||||
double currentPos = 0.0;
|
|
||||||
double velo = 0.0;
|
double velo = 0.0;
|
||||||
double velo1 = 0.0;
|
double velo1 = 0.0;
|
||||||
double velo2 = 0.0;
|
double velo2 = 0.0;
|
||||||
@@ -25,6 +16,10 @@ public class Flywheel {
|
|||||||
boolean steady = false;
|
boolean steady = false;
|
||||||
public Flywheel (HardwareMap hardwareMap) {
|
public Flywheel (HardwareMap hardwareMap) {
|
||||||
robot = new Robot(hardwareMap);
|
robot = new Robot(hardwareMap);
|
||||||
|
shooterPIDF1 = new PIDFCoefficients
|
||||||
|
(robot.shooterPIDF_P, robot.shooterPIDF_I, robot.shooterPIDF_D, robot.shooterPIDF_F);
|
||||||
|
shooterPIDF2 = new PIDFCoefficients
|
||||||
|
(robot.shooterPIDF_P, robot.shooterPIDF_I, robot.shooterPIDF_D, robot.shooterPIDF_F);
|
||||||
}
|
}
|
||||||
|
|
||||||
public double getVelo () {
|
public double getVelo () {
|
||||||
@@ -48,10 +43,6 @@ public class Flywheel {
|
|||||||
robot.shooterPIDF.d = d;
|
robot.shooterPIDF.d = d;
|
||||||
robot.shooterPIDF.f = f;
|
robot.shooterPIDF.f = f;
|
||||||
}
|
}
|
||||||
private double getTimeSeconds ()
|
|
||||||
{
|
|
||||||
return (double) System.currentTimeMillis()/1000.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert from RPM to Ticks per Second
|
// Convert from RPM to Ticks per Second
|
||||||
private double RPM_to_TPS (double RPM) { return (RPM*28.0)/60.0;}
|
private double RPM_to_TPS (double RPM) { return (RPM*28.0)/60.0;}
|
||||||
@@ -62,19 +53,20 @@ public class Flywheel {
|
|||||||
public double manageFlywheel(double commandedVelocity) {
|
public double manageFlywheel(double commandedVelocity) {
|
||||||
targetVelocity = commandedVelocity;
|
targetVelocity = commandedVelocity;
|
||||||
|
|
||||||
// Turn PIDF for Target Velocities
|
// Add code here to set PIDF based on desired RPM
|
||||||
//robot.shooterPIDF.p = P;
|
//robot.shooterPIDF.p = P;
|
||||||
//robot.shooterPIDF.i = I;
|
//robot.shooterPIDF.i = I;
|
||||||
//robot.shooterPIDF.d = D;
|
//robot.shooterPIDF.d = D;
|
||||||
//robot.shooterPIDF.f = F;
|
//robot.shooterPIDF.f = F;
|
||||||
robot.shooter1.setPIDFCoefficients(DcMotor.RunMode.RUN_USING_ENCODER, robot.shooterPIDF);
|
|
||||||
robot.shooter2.setPIDFCoefficients(DcMotor.RunMode.RUN_USING_ENCODER, robot.shooterPIDF);
|
robot.shooter1.setPIDFCoefficients(DcMotor.RunMode.RUN_USING_ENCODER, shooterPIDF1);
|
||||||
|
robot.shooter2.setPIDFCoefficients(DcMotor.RunMode.RUN_USING_ENCODER, shooterPIDF2);
|
||||||
robot.shooter1.setVelocity(RPM_to_TPS(targetVelocity));
|
robot.shooter1.setVelocity(RPM_to_TPS(targetVelocity));
|
||||||
robot.shooter2.setVelocity(RPM_to_TPS(targetVelocity));
|
robot.shooter2.setVelocity(RPM_to_TPS(targetVelocity));
|
||||||
|
|
||||||
// Record Current Velocity
|
// Record Current Velocity
|
||||||
velo1 = TPS_to_RPM(robot.shooter1.getVelocity());
|
velo1 = TPS_to_RPM(robot.shooter1.getVelocity());
|
||||||
velo2 = TPS_to_RPM(robot.shooter1.getVelocity()); // Possible error: should it be shooter2 not shooter1?
|
velo2 = TPS_to_RPM(robot.shooter2.getVelocity());
|
||||||
velo = Math.max(velo1,velo2);
|
velo = Math.max(velo1,velo2);
|
||||||
|
|
||||||
// really should be a running average of the last 5
|
// really should be a running average of the last 5
|
||||||
|
|||||||
@@ -71,7 +71,6 @@ public class PositionalServoProgrammer extends LinearOpMode {
|
|||||||
TELE.addData("spindexer voltage 2", robot.spin2Pos.getVoltage());
|
TELE.addData("spindexer voltage 2", robot.spin2Pos.getVoltage());
|
||||||
TELE.addData("hood pos", robot.hood.getPosition());
|
TELE.addData("hood pos", robot.hood.getPosition());
|
||||||
TELE.addData("transferServo voltage", robot.transferServoPos.getVoltage());
|
TELE.addData("transferServo voltage", robot.transferServoPos.getVoltage());
|
||||||
TELE.addData("turret voltage", robot.turr1Pos.getCurrentPosition());
|
|
||||||
TELE.addData("spindexer pow", robot.spin1.getPower());
|
TELE.addData("spindexer pow", robot.spin1.getPower());
|
||||||
TELE.update();
|
TELE.update();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.firstinspires.ftc.teamcode.utils;
|
package org.firstinspires.ftc.teamcode.utils;
|
||||||
|
|
||||||
|
import com.acmerobotics.dashboard.config.Config;
|
||||||
import com.qualcomm.hardware.limelightvision.Limelight3A;
|
import com.qualcomm.hardware.limelightvision.Limelight3A;
|
||||||
import com.qualcomm.hardware.rev.RevColorSensorV3;
|
import com.qualcomm.hardware.rev.RevColorSensorV3;
|
||||||
import com.qualcomm.robotcore.hardware.AnalogInput;
|
import com.qualcomm.robotcore.hardware.AnalogInput;
|
||||||
@@ -14,10 +15,13 @@ import com.qualcomm.robotcore.hardware.Servo;
|
|||||||
import org.firstinspires.ftc.robotcore.external.hardware.camera.WebcamName;
|
import org.firstinspires.ftc.robotcore.external.hardware.camera.WebcamName;
|
||||||
import org.firstinspires.ftc.vision.apriltag.AprilTagProcessor;
|
import org.firstinspires.ftc.vision.apriltag.AprilTagProcessor;
|
||||||
|
|
||||||
|
@Config
|
||||||
public class Robot {
|
public class Robot {
|
||||||
|
|
||||||
//Initialize Public Components
|
//Initialize Public Components
|
||||||
|
|
||||||
|
public static boolean usingLimelight = false;
|
||||||
|
public static boolean usingCamera = true;
|
||||||
public DcMotorEx frontLeft;
|
public DcMotorEx frontLeft;
|
||||||
public DcMotorEx frontRight;
|
public DcMotorEx frontRight;
|
||||||
public DcMotorEx backLeft;
|
public DcMotorEx backLeft;
|
||||||
@@ -29,8 +33,7 @@ public class Robot {
|
|||||||
public double shooterPIDF_I = 0.6;
|
public double shooterPIDF_I = 0.6;
|
||||||
public double shooterPIDF_D = 5.0;
|
public double shooterPIDF_D = 5.0;
|
||||||
public double shooterPIDF_F = 10.0;
|
public double shooterPIDF_F = 10.0;
|
||||||
|
public double[] shooterPIDF_StepSizes = {10.0, 1.0, 0.001, 0.0001};
|
||||||
public double[] shooterPIDF_StepSizes = {10.0,1.0,0.001, 0.0001};
|
|
||||||
public DcMotorEx shooter1;
|
public DcMotorEx shooter1;
|
||||||
public DcMotorEx shooter2;
|
public DcMotorEx shooter2;
|
||||||
public Servo hood;
|
public Servo hood;
|
||||||
@@ -41,7 +44,7 @@ public class Robot {
|
|||||||
public CRServo spin2;
|
public CRServo spin2;
|
||||||
public AnalogInput spin1Pos;
|
public AnalogInput spin1Pos;
|
||||||
public AnalogInput spin2Pos;
|
public AnalogInput spin2Pos;
|
||||||
public DcMotorEx turr1Pos;
|
public AnalogInput turr1Pos;
|
||||||
public AnalogInput transferServoPos;
|
public AnalogInput transferServoPos;
|
||||||
public AprilTagProcessor aprilTagProcessor;
|
public AprilTagProcessor aprilTagProcessor;
|
||||||
public WebcamName webcam;
|
public WebcamName webcam;
|
||||||
@@ -50,10 +53,6 @@ public class Robot {
|
|||||||
public RevColorSensorV3 color3;
|
public RevColorSensorV3 color3;
|
||||||
public Limelight3A limelight;
|
public Limelight3A limelight;
|
||||||
|
|
||||||
public static boolean usingLimelight = true;
|
|
||||||
|
|
||||||
public static boolean usingCamera = true;
|
|
||||||
|
|
||||||
public Robot(HardwareMap hardwareMap) {
|
public Robot(HardwareMap hardwareMap) {
|
||||||
|
|
||||||
//Define components w/ hardware map
|
//Define components w/ hardware map
|
||||||
@@ -77,7 +76,7 @@ public class Robot {
|
|||||||
shooter2 = hardwareMap.get(DcMotorEx.class, "shooter2");
|
shooter2 = hardwareMap.get(DcMotorEx.class, "shooter2");
|
||||||
//TODO: figure out which shooter motor is reversed using ShooterTest and change it in code @KeshavAnandCode
|
//TODO: figure out which shooter motor is reversed using ShooterTest and change it in code @KeshavAnandCode
|
||||||
shooter1.setDirection(DcMotorSimple.Direction.REVERSE);
|
shooter1.setDirection(DcMotorSimple.Direction.REVERSE);
|
||||||
shooterPIDF = new PIDFCoefficients(shooterPIDF_P,shooterPIDF_I , shooterPIDF_D, shooterPIDF_F);
|
shooterPIDF = new PIDFCoefficients(shooterPIDF_P, shooterPIDF_I, shooterPIDF_D, shooterPIDF_F);
|
||||||
shooter1.setMode(DcMotor.RunMode.RUN_USING_ENCODER);
|
shooter1.setMode(DcMotor.RunMode.RUN_USING_ENCODER);
|
||||||
shooter1.setPIDFCoefficients(DcMotor.RunMode.RUN_USING_ENCODER, shooterPIDF);
|
shooter1.setPIDFCoefficients(DcMotor.RunMode.RUN_USING_ENCODER, shooterPIDF);
|
||||||
shooter2.setMode(DcMotor.RunMode.RUN_USING_ENCODER);
|
shooter2.setMode(DcMotor.RunMode.RUN_USING_ENCODER);
|
||||||
@@ -89,7 +88,7 @@ public class Robot {
|
|||||||
|
|
||||||
turr2 = hardwareMap.get(Servo.class, "t2");
|
turr2 = hardwareMap.get(Servo.class, "t2");
|
||||||
|
|
||||||
turr1Pos = intake; // Encoder of turret plugged in intake port
|
turr1Pos = hardwareMap.get(AnalogInput.class, "t1Pos"); // Encoder of turret plugged in intake port
|
||||||
|
|
||||||
//TODO: check spindexer configuration (both servo and analog input) - check comments in PositionalServoProgrammer
|
//TODO: check spindexer configuration (both servo and analog input) - check comments in PositionalServoProgrammer
|
||||||
spin1 = hardwareMap.get(CRServo.class, "spin1");
|
spin1 = hardwareMap.get(CRServo.class, "spin1");
|
||||||
@@ -118,9 +117,9 @@ public class Robot {
|
|||||||
|
|
||||||
color3 = hardwareMap.get(RevColorSensorV3.class, "c3");
|
color3 = hardwareMap.get(RevColorSensorV3.class, "c3");
|
||||||
|
|
||||||
if (usingLimelight){
|
if (usingLimelight) {
|
||||||
limelight = hardwareMap.get(Limelight3A.class, "limelight");
|
limelight = hardwareMap.get(Limelight3A.class, "limelight");
|
||||||
} else if (usingCamera){
|
} else if (usingCamera) {
|
||||||
webcam = hardwareMap.get(WebcamName.class, "Webcam 1");
|
webcam = hardwareMap.get(WebcamName.class, "Webcam 1");
|
||||||
aprilTagProcessor = AprilTagProcessor.easyCreateWithDefaults();
|
aprilTagProcessor = AprilTagProcessor.easyCreateWithDefaults();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,17 +44,15 @@ public class Servos {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public double getTurrPos() {
|
public double getTurrPos() {
|
||||||
return (double) ((double) robot.turr1Pos.getCurrentPosition() / 1024.0) * ((double) 44.0 / (double) 77.0);
|
return 1.0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public double setTurrPos(double pos) {
|
public double setTurrPos(double pos) {
|
||||||
turretPID.setPIDF(turrP, turrI, turrD, turrF);
|
return 1.0;
|
||||||
|
|
||||||
return spinPID.calculate(this.getTurrPos(), pos);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean turretEqual(double pos) {
|
public boolean turretEqual(double pos) {
|
||||||
return Math.abs(pos - this.getTurrPos()) < 0.01;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,7 +52,9 @@ public class Spindexer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
enum IntakeState {
|
enum IntakeState {
|
||||||
UNKNOWN,
|
UNKNOWN_START,
|
||||||
|
UNKNOWN_MOVE,
|
||||||
|
UNKNOWN_DETECT,
|
||||||
INTAKE,
|
INTAKE,
|
||||||
FINDNEXT,
|
FINDNEXT,
|
||||||
MOVING,
|
MOVING,
|
||||||
@@ -62,8 +64,8 @@ public class Spindexer {
|
|||||||
SHOOTWAIT,
|
SHOOTWAIT,
|
||||||
};
|
};
|
||||||
|
|
||||||
public IntakeState currentIntakeState = IntakeState.UNKNOWN;
|
public IntakeState currentIntakeState = IntakeState.UNKNOWN_START;
|
||||||
|
public int unknownColorDetect = 0;
|
||||||
enum BallColor {
|
enum BallColor {
|
||||||
UNKNOWN,
|
UNKNOWN,
|
||||||
GREEN,
|
GREEN,
|
||||||
@@ -131,13 +133,13 @@ public class Spindexer {
|
|||||||
for (int i = 0; i < 3; i++) {
|
for (int i = 0; i < 3; i++) {
|
||||||
resetBallPosition(i);
|
resetBallPosition(i);
|
||||||
}
|
}
|
||||||
currentIntakeState = IntakeState.UNKNOWN;
|
currentIntakeState = IntakeState.UNKNOWN_START;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Detects if a ball is found and what color.
|
// Detects if a ball is found and what color.
|
||||||
// Returns true is there was a new ball found in Position 1
|
// Returns true is there was a new ball found in Position 1
|
||||||
// FIXIT: Reduce number of times that we read the color sensors for loop times.
|
// FIXIT: Reduce number of times that we read the color sensors for loop times.
|
||||||
public boolean detectBalls() {
|
public boolean detectBalls(boolean detectRearColor, boolean detectFrontColor) {
|
||||||
|
|
||||||
boolean newPos1Detection = false;
|
boolean newPos1Detection = false;
|
||||||
int spindexerBallPos = 0;
|
int spindexerBallPos = 0;
|
||||||
@@ -153,6 +155,7 @@ public class Spindexer {
|
|||||||
// Mark Ball Found
|
// Mark Ball Found
|
||||||
newPos1Detection = true;
|
newPos1Detection = true;
|
||||||
|
|
||||||
|
if (detectRearColor) {
|
||||||
// Detect which color
|
// Detect which color
|
||||||
double green = robot.color1.getNormalizedColors().green;
|
double green = robot.color1.getNormalizedColors().green;
|
||||||
double red = robot.color1.getNormalizedColors().red;
|
double red = robot.color1.getNormalizedColors().red;
|
||||||
@@ -167,24 +170,26 @@ public class Spindexer {
|
|||||||
ballPositions[commandedIntakePosition].ballColor = BallColor.GREEN; // purple
|
ballPositions[commandedIntakePosition].ballColor = BallColor.GREEN; // purple
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// Position 2
|
// Position 2
|
||||||
// Find which ball position this is in the spindexer
|
// Find which ball position this is in the spindexer
|
||||||
spindexerBallPos = RotatedBallPositions[commandedIntakePosition][RotatedBallPositionNames.FRONTDRIVER.ordinal()];
|
spindexerBallPos = RotatedBallPositions[commandedIntakePosition][RotatedBallPositionNames.FRONTDRIVER.ordinal()];
|
||||||
if (distanceFrontDriver < 60) {
|
if (distanceFrontDriver < 60) {
|
||||||
// reset FoundEmpty because looking for 3 in a row before reset
|
// reset FoundEmpty because looking for 3 in a row before reset
|
||||||
ballPositions[spindexerBallPos].foundEmpty = 0;
|
ballPositions[spindexerBallPos].foundEmpty = 0;
|
||||||
// FIXIT: Comment out for now due to loop time concerns
|
if (detectFrontColor) {
|
||||||
// double green = robot.color2.getNormalizedColors().green;
|
double green = robot.color2.getNormalizedColors().green;
|
||||||
// double red = robot.color2.getNormalizedColors().red;
|
double red = robot.color2.getNormalizedColors().red;
|
||||||
// double blue = robot.color2.getNormalizedColors().blue;
|
double blue = robot.color2.getNormalizedColors().blue;
|
||||||
//
|
|
||||||
// double gP = green / (green + red + blue);
|
|
||||||
|
|
||||||
// if (gP >= 0.4) {
|
double gP = green / (green + red + blue);
|
||||||
// b2 = 2; // purple
|
|
||||||
// } else {
|
if (gP >= 0.4) {
|
||||||
// b2 = 1; // green
|
ballPositions[spindexerBallPos].ballColor = BallColor.PURPLE; // purple
|
||||||
// }
|
} else {
|
||||||
|
ballPositions[spindexerBallPos].ballColor = BallColor.GREEN; // purple
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!ballPositions[spindexerBallPos].isEmpty) {
|
if (!ballPositions[spindexerBallPos].isEmpty) {
|
||||||
if (ballPositions[spindexerBallPos].foundEmpty > 3) {
|
if (ballPositions[spindexerBallPos].foundEmpty > 3) {
|
||||||
@@ -201,18 +206,19 @@ public class Spindexer {
|
|||||||
|
|
||||||
// reset FoundEmpty because looking for 3 in a row before reset
|
// reset FoundEmpty because looking for 3 in a row before reset
|
||||||
ballPositions[spindexerBallPos].foundEmpty = 0;
|
ballPositions[spindexerBallPos].foundEmpty = 0;
|
||||||
// FIXIT: Comment out for now due to loop time concerns
|
if (detectFrontColor) {
|
||||||
// double green = robot.color3.getNormalizedColors().green;
|
double green = robot.color3.getNormalizedColors().green;
|
||||||
// double red = robot.color3.getNormalizedColors().red;
|
double red = robot.color3.getNormalizedColors().red;
|
||||||
// double blue = robot.color3.getNormalizedColors().blue;
|
double blue = robot.color3.getNormalizedColors().blue;
|
||||||
|
|
||||||
// double gP = green / (green + red + blue);
|
double gP = green / (green + red + blue);
|
||||||
|
|
||||||
// if (gP >= 0.4) {
|
if (gP >= 0.4) {
|
||||||
// b3 = 2; // purple
|
ballPositions[spindexerBallPos].ballColor = BallColor.PURPLE; // purple
|
||||||
// } else {
|
} else {
|
||||||
// b3 = 1; // green
|
ballPositions[spindexerBallPos].ballColor = BallColor.GREEN; // purple
|
||||||
// }
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!ballPositions[spindexerBallPos].isEmpty) {
|
if (!ballPositions[spindexerBallPos].isEmpty) {
|
||||||
if (ballPositions[spindexerBallPos].foundEmpty > 3) {
|
if (ballPositions[spindexerBallPos].foundEmpty > 3) {
|
||||||
@@ -255,15 +261,35 @@ public class Spindexer {
|
|||||||
public boolean processIntake() {
|
public boolean processIntake() {
|
||||||
|
|
||||||
switch (currentIntakeState) {
|
switch (currentIntakeState) {
|
||||||
case UNKNOWN:
|
case UNKNOWN_START:
|
||||||
// For now just set position ONE if UNKNOWN
|
// For now just set position ONE if UNKNOWN
|
||||||
commandedIntakePosition = 0;
|
commandedIntakePosition = 0;
|
||||||
servos.setSpinPos(intakePositions[0]);
|
servos.setSpinPos(intakePositions[0]);
|
||||||
currentIntakeState = Spindexer.IntakeState.MOVING;
|
currentIntakeState = Spindexer.IntakeState.UNKNOWN_MOVE;
|
||||||
|
break;
|
||||||
|
case UNKNOWN_MOVE:
|
||||||
|
// Stopping when we get to the new position
|
||||||
|
if (servos.spinEqual(intakePositions[commandedIntakePosition])) {
|
||||||
|
currentIntakeState = Spindexer.IntakeState.UNKNOWN_DETECT;
|
||||||
|
stopSpindexer();
|
||||||
|
detectBalls(true, true);
|
||||||
|
unknownColorDetect = 0;
|
||||||
|
} else {
|
||||||
|
// Keep moving the spindexer
|
||||||
|
moveSpindexerToPos(intakePositions[commandedIntakePosition]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case UNKNOWN_DETECT:
|
||||||
|
if (unknownColorDetect >5) {
|
||||||
|
currentIntakeState = Spindexer.IntakeState.FINDNEXT;
|
||||||
|
} else {
|
||||||
|
detectBalls(true, true);
|
||||||
|
unknownColorDetect++;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case INTAKE:
|
case INTAKE:
|
||||||
// Ready for intake and Detecting a New Ball
|
// Ready for intake and Detecting a New Ball
|
||||||
if (detectBalls()) {
|
if (detectBalls(true, false)) {
|
||||||
ballPositions[commandedIntakePosition].isEmpty = false;
|
ballPositions[commandedIntakePosition].isEmpty = false;
|
||||||
currentIntakeState = Spindexer.IntakeState.FINDNEXT;
|
currentIntakeState = Spindexer.IntakeState.FINDNEXT;
|
||||||
} else {
|
} else {
|
||||||
@@ -311,7 +337,7 @@ public class Spindexer {
|
|||||||
if (servos.spinEqual(intakePositions[commandedIntakePosition])) {
|
if (servos.spinEqual(intakePositions[commandedIntakePosition])) {
|
||||||
currentIntakeState = Spindexer.IntakeState.INTAKE;
|
currentIntakeState = Spindexer.IntakeState.INTAKE;
|
||||||
stopSpindexer();
|
stopSpindexer();
|
||||||
detectBalls();
|
detectBalls(false, false);
|
||||||
} else {
|
} else {
|
||||||
// Keep moving the spindexer
|
// Keep moving the spindexer
|
||||||
moveSpindexerToPos(intakePositions[commandedIntakePosition]);
|
moveSpindexerToPos(intakePositions[commandedIntakePosition]);
|
||||||
@@ -320,7 +346,7 @@ public class Spindexer {
|
|||||||
|
|
||||||
case FULL:
|
case FULL:
|
||||||
// Double Check Colors
|
// Double Check Colors
|
||||||
detectBalls();
|
detectBalls(false, false); // Minimize hardware calls
|
||||||
if (ballPositions[0].isEmpty || ballPositions[1].isEmpty || ballPositions[2].isEmpty) {
|
if (ballPositions[0].isEmpty || ballPositions[1].isEmpty || ballPositions[2].isEmpty) {
|
||||||
// Error handling found an empty spot, get it ready for a ball
|
// Error handling found an empty spot, get it ready for a ball
|
||||||
currentIntakeState = Spindexer.IntakeState.FINDNEXT;
|
currentIntakeState = Spindexer.IntakeState.FINDNEXT;
|
||||||
@@ -378,7 +404,7 @@ public class Spindexer {
|
|||||||
if (servos.spinEqual(intakePositions[commandedIntakePosition])) {
|
if (servos.spinEqual(intakePositions[commandedIntakePosition])) {
|
||||||
currentIntakeState = Spindexer.IntakeState.INTAKE;
|
currentIntakeState = Spindexer.IntakeState.INTAKE;
|
||||||
stopSpindexer();
|
stopSpindexer();
|
||||||
detectBalls();
|
detectBalls(true, false);
|
||||||
} else {
|
} else {
|
||||||
// Keep moving the spindexer
|
// Keep moving the spindexer
|
||||||
moveSpindexerToPos(intakePositions[commandedIntakePosition]);
|
moveSpindexerToPos(intakePositions[commandedIntakePosition]);
|
||||||
|
|||||||
@@ -0,0 +1,141 @@
|
|||||||
|
package org.firstinspires.ftc.teamcode.utils;
|
||||||
|
|
||||||
|
import android.provider.Settings;
|
||||||
|
|
||||||
|
import com.acmerobotics.dashboard.telemetry.MultipleTelemetry;
|
||||||
|
import com.qualcomm.robotcore.hardware.DcMotor;
|
||||||
|
import com.qualcomm.robotcore.hardware.HardwareMap;
|
||||||
|
|
||||||
|
public class Targeting {
|
||||||
|
MultipleTelemetry TELE;
|
||||||
|
|
||||||
|
double cancelOffsetX = 7.071067811;
|
||||||
|
double cancelOffsetY = 7.071067811;
|
||||||
|
double unitConversionFactor = 0.95;
|
||||||
|
|
||||||
|
int tileSize = 24; //inches
|
||||||
|
|
||||||
|
public double robotInchesX, robotInchesY = 0.0;
|
||||||
|
|
||||||
|
public int robotGridX, robotGridY = 0;
|
||||||
|
|
||||||
|
|
||||||
|
public static class Settings {
|
||||||
|
public double flywheelRPM = 0.0;
|
||||||
|
public double hoodAngle = 0.0;
|
||||||
|
|
||||||
|
public Settings (double flywheelRPM, double hoodAngle) {
|
||||||
|
this.flywheelRPM = flywheelRPM;
|
||||||
|
this.hoodAngle = hoodAngle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Known settings discovered using shooter test.
|
||||||
|
// Keep the fidelity at 1 floor tile for now but we could also half it if more
|
||||||
|
// accuracy is needed.
|
||||||
|
public static final Settings[][] KNOWNTARGETING;
|
||||||
|
static {
|
||||||
|
KNOWNTARGETING = new Settings[6][6];
|
||||||
|
// ROW 0 - Closet to the goals
|
||||||
|
KNOWNTARGETING[0][0] = new Settings (3000.0, 0.25);
|
||||||
|
KNOWNTARGETING[0][1] = new Settings (3001.0, 0.25);
|
||||||
|
KNOWNTARGETING[0][2] = new Settings (3002.0, 0.25);
|
||||||
|
KNOWNTARGETING[0][3] = new Settings (3302.0, 0.2);
|
||||||
|
KNOWNTARGETING[0][4] = new Settings (3503.0, 0.15);
|
||||||
|
KNOWNTARGETING[0][5] = new Settings (3505.0, 0.15);
|
||||||
|
// ROW 1
|
||||||
|
KNOWNTARGETING[1][0] = new Settings (3010.0, 0.25);
|
||||||
|
KNOWNTARGETING[1][1] = new Settings (3011.0, 0.25);
|
||||||
|
KNOWNTARGETING[1][2] = new Settings (3012.0, 0.25);
|
||||||
|
KNOWNTARGETING[1][3] = new Settings (3313.0, 0.15);
|
||||||
|
KNOWNTARGETING[1][4] = new Settings (3514.0, 0.15);
|
||||||
|
KNOWNTARGETING[1][5] = new Settings (3515.0, 0.15);
|
||||||
|
// ROW 2
|
||||||
|
KNOWNTARGETING[2][0] = new Settings (3020.0, 0.1);
|
||||||
|
KNOWNTARGETING[2][1] = new Settings (3000.0, 0.25);
|
||||||
|
KNOWNTARGETING[2][2] = new Settings (3000.0, 0.15);
|
||||||
|
KNOWNTARGETING[2][3] = new Settings (3000.0, 0.15);
|
||||||
|
KNOWNTARGETING[2][4] = new Settings (3524.0, 0.15);
|
||||||
|
KNOWNTARGETING[2][5] = new Settings (3525.0, 0.15);
|
||||||
|
// ROW 3
|
||||||
|
KNOWNTARGETING[3][0] = new Settings (3030.0, 0.15);
|
||||||
|
KNOWNTARGETING[3][1] = new Settings (3031.0, 0.15);
|
||||||
|
KNOWNTARGETING[3][2] = new Settings (3000.0, 0.15);
|
||||||
|
KNOWNTARGETING[3][3] = new Settings (3000.0, 0.15);
|
||||||
|
KNOWNTARGETING[3][4] = new Settings (3000.0, 0.03);
|
||||||
|
KNOWNTARGETING[3][5] = new Settings (3535.0, 0.1);
|
||||||
|
// ROW 4
|
||||||
|
KNOWNTARGETING[4][0] = new Settings (4540.0, 0.1);
|
||||||
|
KNOWNTARGETING[4][1] = new Settings (4541.0, 0.1);
|
||||||
|
KNOWNTARGETING[4][2] = new Settings (4542.0, 0.1);
|
||||||
|
KNOWNTARGETING[4][3] = new Settings (4543.0, 0.1);
|
||||||
|
KNOWNTARGETING[4][4] = new Settings (4544.0, 0.1);
|
||||||
|
KNOWNTARGETING[4][5] = new Settings (4545.0, 0.1);
|
||||||
|
// ROW 1
|
||||||
|
KNOWNTARGETING[5][0] = new Settings (4550.0, 0.1);
|
||||||
|
KNOWNTARGETING[5][1] = new Settings (4551.0, 0.1);
|
||||||
|
KNOWNTARGETING[5][2] = new Settings (4552.0, 0.1);
|
||||||
|
KNOWNTARGETING[5][3] = new Settings (4553.0, 0.1);
|
||||||
|
KNOWNTARGETING[5][4] = new Settings (4554.0, 0.1);
|
||||||
|
KNOWNTARGETING[5][5] = new Settings (4555.0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Targeting()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public Settings calculateSettings(double robotX, double robotY, double robotHeading, double robotVelocity, boolean interpolate) {
|
||||||
|
Settings recommendedSettings = new Settings(0.0, 0.0);
|
||||||
|
|
||||||
|
double cos45 = Math.cos(Math.toRadians(-45));
|
||||||
|
double sin45 = Math.sin(Math.toRadians(-45));
|
||||||
|
double rotatedY = (robotX - 40.0) * sin45 + (robotY + 7.0) * cos45;
|
||||||
|
double rotatedX = (robotX - 40.0) * cos45 - (robotY + 7.0) * sin45;
|
||||||
|
|
||||||
|
// Convert robot coordinates to inches
|
||||||
|
robotInchesX = rotatedX * unitConversionFactor;
|
||||||
|
robotInchesY = rotatedY * unitConversionFactor;
|
||||||
|
|
||||||
|
// Find approximate location in the grid
|
||||||
|
robotGridX = Math.abs(Math.floorDiv((int) robotInchesX, tileSize) + 1);
|
||||||
|
robotGridY = Math.abs(Math.floorDiv((int) robotInchesY, tileSize));
|
||||||
|
|
||||||
|
//clamp
|
||||||
|
robotGridX = Math.max(0, Math.min(gridX, KNOWNTARGETING[0].length - 1));
|
||||||
|
robotGridY = Math.max(0, Math.min(gridY, KNOWNTARGETING.length - 1));
|
||||||
|
|
||||||
|
// basic search
|
||||||
|
if(!interpolate) {
|
||||||
|
if ((robotGridY < 6) && (robotGridX <6)) {
|
||||||
|
recommendedSettings.flywheelRPM = KNOWNTARGETING[robotGridY][robotGridX].flywheelRPM;
|
||||||
|
recommendedSettings.hoodAngle = KNOWNTARGETING[robotGridY][robotGridX].hoodAngle;
|
||||||
|
}
|
||||||
|
return recommendedSettings;
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// bilinear interpolation
|
||||||
|
int x0 = robotGridX;
|
||||||
|
int x1 = Math.min(x0 + 1, KNOWNTARGETING[0].length - 1);
|
||||||
|
int y0 = gridY;
|
||||||
|
int y1 = Math.min(y0 + 1, KNOWNTARGETING.length - 1);
|
||||||
|
|
||||||
|
double x = (robotInchesX - (x0 * tileSize)) / tileSize;
|
||||||
|
double y = (robotInchesY - (y0 * tileSize)) / tileSize;
|
||||||
|
|
||||||
|
double rpm00 = KNOWNTARGETING[y0][x0].flywheelRPM;
|
||||||
|
double rpm10 = KNOWNTARGETING[y0][x1].flywheelRPM;
|
||||||
|
double rpm01 = KNOWNTARGETING[y1][x0].flywheelRPM;
|
||||||
|
double rpm11 = KNOWNTARGETING[y1][x1].flywheelRPM;
|
||||||
|
|
||||||
|
double angle00 = KNOWNTARGETING[y0][x0].hoodAngle;
|
||||||
|
double angle10 = KNOWNTARGETING[y0][x1].hoodAngle;
|
||||||
|
double angle01 = KNOWNTARGETING[y1][x0].hoodAngle;
|
||||||
|
double angle11 = KNOWNTARGETING[y1][x1].hoodAngle;
|
||||||
|
|
||||||
|
recommendedSettings.flywheelRPM = (1 - x) * (1 - y) * rpm00 + x * (1 - y) * rpm10 + (1 - x) * y * rpm01 + x * y * rpm11;
|
||||||
|
recommendedSettings.hoodAngle = (1 - x) * (1 - y) * angle00 + x * (1 - y) * angle10 + (1 - x) * y * angle01 + x * y * angle11;
|
||||||
|
|
||||||
|
return recommendedSettings;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,100 @@
|
|||||||
|
package org.firstinspires.ftc.teamcode.utils;
|
||||||
|
|
||||||
|
import static org.firstinspires.ftc.teamcode.constants.Color.redAlliance;
|
||||||
|
|
||||||
|
import com.acmerobotics.dashboard.config.Config;
|
||||||
|
import com.acmerobotics.dashboard.telemetry.MultipleTelemetry;
|
||||||
|
import com.acmerobotics.roadrunner.Pose2d;
|
||||||
|
import com.qualcomm.robotcore.util.Range;
|
||||||
|
|
||||||
|
import org.firstinspires.ftc.vision.apriltag.AprilTagDetection;
|
||||||
|
|
||||||
|
@Config
|
||||||
|
public class Turret {
|
||||||
|
|
||||||
|
public static double turrDefault = 0.4;
|
||||||
|
public static double turretRange = 0.6;
|
||||||
|
public static double turrMin = 0.2;
|
||||||
|
public static double turrMax = 0.8;
|
||||||
|
|
||||||
|
public static double turretTolerance = 0.02;
|
||||||
|
|
||||||
|
public static double cameraBearingEqual = 1.5;
|
||||||
|
public static double errorLearningRate = 0.02; // must be low
|
||||||
|
public static double maxOffsetDeg = 30.0;
|
||||||
|
|
||||||
|
private final Robot robot;
|
||||||
|
private final MultipleTelemetry TELE;
|
||||||
|
private final AprilTagWebcam webcam;
|
||||||
|
|
||||||
|
private int obeliskID = 0;
|
||||||
|
private double offsetDeg = 0.0;
|
||||||
|
|
||||||
|
public Turret(Robot rob, MultipleTelemetry tele, AprilTagWebcam cam) {
|
||||||
|
this.robot = rob;
|
||||||
|
this.TELE = tele;
|
||||||
|
this.webcam = cam;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getTurretPos() {
|
||||||
|
return robot.turr1Pos.getVoltage() / 3.3;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void manualSetTurret(double pos) {
|
||||||
|
pos = Range.clip(pos, turrMin, turrMax);
|
||||||
|
robot.turr1.setPosition(pos);
|
||||||
|
robot.turr2.setPosition(1.0 - pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean turretAt(double pos) {
|
||||||
|
return Math.abs(pos - getTurretPos()) < turretTolerance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getBearingDeg() {
|
||||||
|
AprilTagDetection tag =
|
||||||
|
redAlliance ? webcam.getTagById(24) : webcam.getTagById(20);
|
||||||
|
return (tag != null) ? tag.ftcPose.bearing : Double.NaN;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int detectObelisk() {
|
||||||
|
if (webcam.getTagById(21) != null) obeliskID = 21;
|
||||||
|
else if (webcam.getTagById(22) != null) obeliskID = 22;
|
||||||
|
else if (webcam.getTagById(23) != null) obeliskID = 23;
|
||||||
|
return obeliskID;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getObeliskID() {
|
||||||
|
return obeliskID;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void trackGoal(Pose2d deltaPos) {
|
||||||
|
|
||||||
|
double turretAngleDeg = Math.toDegrees(
|
||||||
|
Math.atan2(deltaPos.position.y, deltaPos.position.x)
|
||||||
|
);
|
||||||
|
|
||||||
|
double bearingDeg = getBearingDeg();
|
||||||
|
|
||||||
|
if (!Double.isNaN(bearingDeg) &&
|
||||||
|
Math.abs(bearingDeg) < cameraBearingEqual) {
|
||||||
|
|
||||||
|
offsetDeg -= bearingDeg * errorLearningRate;
|
||||||
|
offsetDeg = Range.clip(offsetDeg, -maxOffsetDeg, maxOffsetDeg);
|
||||||
|
}
|
||||||
|
|
||||||
|
turretAngleDeg += offsetDeg;
|
||||||
|
|
||||||
|
double turretPos =
|
||||||
|
turrDefault + (turretAngleDeg / 180.0) * turretRange;
|
||||||
|
|
||||||
|
turretPos = Range.clip(turretPos, turrMin, turrMax);
|
||||||
|
|
||||||
|
robot.turr1.setPosition(turretPos);
|
||||||
|
robot.turr2.setPosition(1.0 - turretPos);
|
||||||
|
|
||||||
|
TELE.addData("Turret Angle (deg)", turretAngleDeg);
|
||||||
|
TELE.addData("Offset (deg)", offsetDeg);
|
||||||
|
TELE.addData("Tag Bearing (deg)", bearingDeg);
|
||||||
|
TELE.addData("Turret Servo", turretPos);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user