Compare commits
6 Commits
c90732ff53
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 41aebd18ab | |||
| d9e6b12cca | |||
| 4df0ef79aa | |||
| 83d6cefc56 | |||
| 22dd346d26 | |||
| d3ec25b8dc |
@@ -15,6 +15,10 @@ import com.qualcomm.robotcore.hardware.Servo;
|
||||
import com.qualcomm.robotcore.hardware.CRServo;
|
||||
import com.qualcomm.robotcore.hardware.SwitchableLight;
|
||||
|
||||
|
||||
import com.qualcomm.robotcore.hardware.ServoImplEx;
|
||||
import com.qualcomm.robotcore.hardware.PwmControl;
|
||||
|
||||
import org.firstinspires.ftc.teamcode.teleOp.Constants;
|
||||
import org.firstinspires.ftc.vision.apriltag.AprilTagDetection;
|
||||
|
||||
@@ -35,12 +39,24 @@ public class hwMap {
|
||||
}
|
||||
|
||||
public static class LedHwMap {
|
||||
public org.firstinspires.ftc.teamcode.Prism.GoBildaPrismDriver led1;
|
||||
public org.firstinspires.ftc.teamcode.Prism.GoBildaPrismDriver led2;
|
||||
private ServoImplEx led;
|
||||
|
||||
public LedHwMap(HardwareMap hardwareMap) {
|
||||
/*led1 = hardwareMap.get(org.firstinspires.ftc.teamcode.Prism.GoBildaPrismDriver.class, "led1");
|
||||
led2 = hardwareMap.get(org.firstinspires.ftc.teamcode.Prism.GoBildaPrismDriver.class, "led2");*/
|
||||
|
||||
led = hardwareMap.get(ServoImplEx.class, Constants.LEDConstants.LED);
|
||||
led.setPwmRange(new PwmControl.PwmRange(500, 2500));
|
||||
}
|
||||
|
||||
public void setLedPos(double pos) {
|
||||
led.setPosition(pos);
|
||||
}
|
||||
|
||||
public void setLedOn(boolean yes) {
|
||||
if (yes) {
|
||||
led.setPwmEnable();
|
||||
} else {
|
||||
led.setPwmDisable();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,7 +105,7 @@ public class hwMap {
|
||||
imu = hardwareMap.get(IMU.class, "imu");
|
||||
IMU.Parameters parameters = new IMU.Parameters(
|
||||
new RevHubOrientationOnRobot(
|
||||
RevHubOrientationOnRobot.LogoFacingDirection.RIGHT,
|
||||
RevHubOrientationOnRobot.LogoFacingDirection.LEFT,
|
||||
RevHubOrientationOnRobot.UsbFacingDirection.UP
|
||||
)
|
||||
);
|
||||
@@ -250,7 +266,7 @@ public class hwMap {
|
||||
private double lastKnownDistance = 0.0;
|
||||
private ElapsedTime noTargetTimer = new ElapsedTime();
|
||||
|
||||
PIDFCoefficients pidfCoefficients = new PIDFCoefficients(22.5, 0, 0.001, 15.6);
|
||||
PIDFCoefficients pidfCoefficients = new PIDFCoefficients(10, 0, 11, 14.3);
|
||||
|
||||
public TurretHwMap(HardwareMap hardwareMap) {
|
||||
noTargetTimer.reset();
|
||||
@@ -283,12 +299,31 @@ public class hwMap {
|
||||
initLimelight(hardwareMap);
|
||||
}
|
||||
|
||||
public void setPIDF(double p, double i, double d, double f) {
|
||||
PIDFCoefficients pidf = new PIDFCoefficients(p, i, d, f);
|
||||
turretLeftMotor.setPIDFCoefficients(DcMotor.RunMode.RUN_USING_ENCODER, pidf);
|
||||
turretRightMotor.setPIDFCoefficients(DcMotor.RunMode.RUN_USING_ENCODER, pidf);
|
||||
public void resetTurret() {
|
||||
turretrotation.setMode(DcMotor.RunMode.STOP_AND_RESET_ENCODER);
|
||||
turretrotation.setMode(DcMotor.RunMode.RUN_WITHOUT_ENCODER);
|
||||
}
|
||||
|
||||
public void setPIDF(double p, double i, double d, double f) {
|
||||
PIDFCoefficients PIDF = new PIDFCoefficients(p, i, d, f);
|
||||
turretLeftMotor.setPIDFCoefficients(DcMotor.RunMode.RUN_USING_ENCODER, PIDF);
|
||||
turretRightMotor.setPIDFCoefficients(DcMotor.RunMode.RUN_USING_ENCODER, PIDF);
|
||||
}
|
||||
|
||||
|
||||
public void enableTurretHold() {
|
||||
turretrotation.setMode(DcMotor.RunMode.RUN_TO_POSITION);
|
||||
}
|
||||
|
||||
public void disableTurretHold() {
|
||||
turretrotation.setMode(DcMotor.RunMode.RUN_WITHOUT_ENCODER);
|
||||
}
|
||||
|
||||
public void runToPos(int target) {
|
||||
turretrotation.setTargetPosition(target);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public double getTurretRotationPosition() {
|
||||
return turretrotation.getCurrentPosition();
|
||||
|
||||
@@ -5,6 +5,7 @@ import com.pedropathing.follower.Follower;
|
||||
import com.pedropathing.geometry.BezierCurve;
|
||||
import com.pedropathing.geometry.BezierLine;
|
||||
import com.pedropathing.geometry.Pose;
|
||||
import com.pedropathing.math.Vector;
|
||||
import com.pedropathing.paths.PathChain;
|
||||
import com.pedropathing.util.Timer;
|
||||
import com.qualcomm.robotcore.eventloop.opmode.Autonomous;
|
||||
@@ -30,80 +31,58 @@ public class Auton {
|
||||
|
||||
@Override
|
||||
public void buildPaths() {
|
||||
// Start Pose
|
||||
startPose = new Pose(59, 9, Math.toRadians(90));
|
||||
follower.setStartingPose(startPose);
|
||||
|
||||
// Poses
|
||||
Pose scorePosePreload = new Pose(59, 15, Math.toRadians(118));
|
||||
Pose scorePoseGeneric = new Pose(59, 15, Math.toRadians(118));
|
||||
Pose set1Inter = new Pose(44, 36, Math.toRadians(180));
|
||||
Pose set1Pick = new Pose(17, 36, Math.toRadians(180));
|
||||
Pose set2Inter = new Pose(41, 60, Math.toRadians(180));
|
||||
Pose set2Pick = new Pose(16, 63, Math.toRadians(180));
|
||||
Pose set2Control1 = new Pose(17.711, 56.837);
|
||||
Pose set2Control2 = new Pose(25.306, 62.677);
|
||||
Pose scoreSet1Control = new Pose(36.621, 19.900);
|
||||
|
||||
// Corner Specific Poses
|
||||
Pose cornerInter = new Pose(9.444, 24.561, Math.toRadians(-90));
|
||||
Pose cornerInterControl = new Pose(37.157, 26.830);
|
||||
Pose cornerArtifact1 = new Pose(12.598, 18.008, Math.toRadians(-135));
|
||||
Pose cornerArtifact1Control = new Pose(11.997, 24.364);
|
||||
Pose cornerArtifact2 = new Pose(10.551, 13.380, Math.toRadians(-160));
|
||||
Pose cornerArtifact3 = new Pose(9.712, 8.993, Math.toRadians(-160));
|
||||
Pose parkPose = new Pose(54.614, 19.545, Math.toRadians(135));
|
||||
|
||||
// --- PATH DEFINITIONS ---
|
||||
scorePreloadPath = follower.pathBuilder()
|
||||
.addPath(new BezierLine(startPose, scorePosePreload))
|
||||
.setLinearHeadingInterpolation(startPose.getHeading(), scorePosePreload.getHeading())
|
||||
.addPath(new BezierLine(new Pose(59, 9), new Pose(59, 15)))
|
||||
.setLinearHeadingInterpolation(Math.toRadians(90), Math.toRadians(118))
|
||||
.build();
|
||||
|
||||
grabSet1Path = follower.pathBuilder()
|
||||
.addPath(new BezierLine(scorePosePreload, set1Inter))
|
||||
.setLinearHeadingInterpolation(scorePosePreload.getHeading(), Math.toRadians(180))
|
||||
.addPath(new BezierLine(set1Inter, set1Pick))
|
||||
.addPath(new BezierLine(new Pose(59, 15), new Pose(44, 36)))
|
||||
.setLinearHeadingInterpolation(Math.toRadians(118), Math.toRadians(180))
|
||||
.addPath(new BezierLine(new Pose(44, 36), new Pose(17, 36)))
|
||||
.setConstantHeadingInterpolation(Math.toRadians(180))
|
||||
.build();
|
||||
|
||||
scoreSet1Path = follower.pathBuilder()
|
||||
.addPath(new BezierCurve(set1Pick, scoreSet1Control, scorePoseGeneric))
|
||||
.setLinearHeadingInterpolation(Math.toRadians(180), scorePoseGeneric.getHeading())
|
||||
.addPath(new BezierCurve(new Pose(17, 36), new Pose(36.621, 19.900), new Pose(59, 15)))
|
||||
.setLinearHeadingInterpolation(Math.toRadians(180), Math.toRadians(118))
|
||||
.build();
|
||||
|
||||
grabSet2Path = follower.pathBuilder()
|
||||
.addPath(new BezierLine(scorePoseGeneric, set2Inter))
|
||||
.setLinearHeadingInterpolation(scorePoseGeneric.getHeading(), Math.toRadians(180))
|
||||
.addPath(new BezierCurve(set2Inter, set2Control1, set2Control2, set2Pick))
|
||||
.addPath(new BezierLine(new Pose(59, 15), new Pose(41, 60)))
|
||||
.setLinearHeadingInterpolation(Math.toRadians(118), Math.toRadians(180))
|
||||
.addPath(new BezierCurve(new Pose(41, 60), new Pose(17.711, 56.837), new Pose(25.306, 62.677), new Pose(16, 63)))
|
||||
.setConstantHeadingInterpolation(Math.toRadians(180))
|
||||
.build();
|
||||
|
||||
scoreSet2Path = follower.pathBuilder()
|
||||
.addPath(new BezierLine(set2Pick, scorePoseGeneric))
|
||||
.setLinearHeadingInterpolation(Math.toRadians(180), scorePoseGeneric.getHeading())
|
||||
.addPath(new BezierLine(new Pose(16, 63), new Pose(59, 15)))
|
||||
.setLinearHeadingInterpolation(Math.toRadians(180), Math.toRadians(118))
|
||||
.build();
|
||||
|
||||
// Corner Sequence
|
||||
grabEndGamePath = follower.pathBuilder()
|
||||
.addPath(new BezierCurve(scorePoseGeneric, cornerInterControl, cornerInter))
|
||||
.setLinearHeadingInterpolation(scorePoseGeneric.getHeading(), Math.toRadians(-90))
|
||||
.addPath(new BezierCurve(cornerInter, cornerArtifact1Control, cornerArtifact1))
|
||||
.setLinearHeadingInterpolation(Math.toRadians(-90), Math.toRadians(-135))
|
||||
.addPath(new BezierLine(cornerArtifact1, cornerArtifact2))
|
||||
.setLinearHeadingInterpolation(Math.toRadians(-135), Math.toRadians(-160))
|
||||
.addPath(new BezierLine(cornerArtifact2, cornerArtifact3))
|
||||
.setConstantHeadingInterpolation(Math.toRadians(-160))
|
||||
.addPath(new BezierCurve(new Pose(59, 15), new Pose(37.157, 26.830), new Pose(10.400, 8)))
|
||||
.setLinearHeadingInterpolation(Math.toRadians(118), Math.toRadians(180))
|
||||
.build();
|
||||
|
||||
scoreEndGamePath = follower.pathBuilder()
|
||||
.addPath(new BezierLine(cornerArtifact3, scorePoseGeneric))
|
||||
.setLinearHeadingInterpolation(Math.toRadians(-160), scorePoseGeneric.getHeading())
|
||||
.addPath(new BezierLine(new Pose(10.400, 8), new Pose(59, 15)))
|
||||
.setLinearHeadingInterpolation(Math.toRadians(180), Math.toRadians(118))
|
||||
.build();
|
||||
|
||||
parkPath = follower.pathBuilder()
|
||||
.addPath(new BezierLine(scorePoseGeneric, parkPose))
|
||||
.setLinearHeadingInterpolation(scorePoseGeneric.getHeading(), parkPose.getHeading())
|
||||
.addPath(new BezierCurve(new Pose(59, 15), new Pose(37.181, 26.706), new Pose(10.400, 27)))
|
||||
.setLinearHeadingInterpolation(Math.toRadians(135), Math.toRadians(180))
|
||||
.addPath(new BezierLine(new Pose(10.400, 27), new Pose(10.439, 17.195)))
|
||||
.setConstantHeadingInterpolation(Math.toRadians(180))
|
||||
.addPath(new BezierLine(new Pose(10.439, 17.195), new Pose(59, 15)))
|
||||
.setLinearHeadingInterpolation(Math.toRadians(180), Math.toRadians(135))
|
||||
.addPath(new BezierLine(new Pose(59, 15), new Pose(54.614, 19.545)))
|
||||
.setConstantHeadingInterpolation(Math.toRadians(135))
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -116,110 +95,82 @@ public class Auton {
|
||||
|
||||
@Override
|
||||
public void buildPaths() {
|
||||
startPose = new Pose(31.5, 137, Math.toRadians(180));
|
||||
startPose = new Pose(21, 124, Math.toRadians(143.5));
|
||||
follower.setStartingPose(startPose);
|
||||
|
||||
// Waypoints
|
||||
Pose preloadScorePose = new Pose(54, 90, Math.toRadians(144));
|
||||
Pose set2DrivePose = new Pose(39, 60, Math.toRadians(180));
|
||||
Pose set2PickPose = new Pose(14, 60, Math.toRadians(180)); // tangential
|
||||
Pose set2ScorePose = new Pose(54, 90, Math.toRadians(144));
|
||||
Pose gate1PickPose = new Pose(10.652, 61.079, Math.toRadians(140));
|
||||
Pose gate1ScorePose = new Pose(54, 90, Math.toRadians(144));
|
||||
Pose gate2PickPose = new Pose(10.652, 61.079, Math.toRadians(140));
|
||||
Pose gate2ScorePose = new Pose(54, 90, Math.toRadians(144));
|
||||
Pose set3DrivePose = new Pose(38.515, 47.156, Math.toRadians(220));
|
||||
Pose set3PickPose = new Pose(16.419, 35.945, Math.toRadians(185));
|
||||
Pose set3ScorePose = new Pose(54, 90, Math.toRadians(144));
|
||||
Pose set1DrivePose = new Pose(39, 84, Math.toRadians(180));
|
||||
Pose set1PickPose = new Pose(29.689, 106.279, Math.toRadians(144));
|
||||
Pose set1ScorePose = new Pose(44, 100, Math.toRadians(148));
|
||||
Pose parkTargetPose = new Pose(36.219, 93.170, Math.toRadians(148));
|
||||
|
||||
// Controls
|
||||
Pose preloadControl = new Pose(27.400, 115.541);
|
||||
Pose set2ScoreControl = new Pose(50.386, 78.923);
|
||||
Pose gate1PickControl = new Pose(40.119, 55.595);
|
||||
Pose gate1ScoreControl = new Pose(41.918, 62.187);
|
||||
Pose gate2PickControl = new Pose(42.081, 61.914);
|
||||
Pose gate2ScoreControl = new Pose(42.318, 61.514);
|
||||
Pose set3PickControl = new Pose(29.622, 37.842);
|
||||
Pose set3ScoreControl = new Pose(9.594, 52.541);
|
||||
Pose set1PickControl = new Pose(14.863, 77.692);
|
||||
|
||||
scorePreloadPath = follower.pathBuilder()
|
||||
.addPath(new BezierCurve(startPose, preloadControl, preloadScorePose))
|
||||
.setLinearHeadingInterpolation(startPose.getHeading(), preloadScorePose.getHeading())
|
||||
.addPath(new BezierLine(new Pose(21, 124), new Pose(54, 90)))
|
||||
.setLinearHeadingInterpolation(Math.toRadians(143.5), Math.toRadians(144))
|
||||
.build();
|
||||
|
||||
driveToSet2Path = follower.pathBuilder()
|
||||
.addPath(new BezierLine(preloadScorePose, set2DrivePose))
|
||||
.setLinearHeadingInterpolation(preloadScorePose.getHeading(), set2DrivePose.getHeading())
|
||||
.addPath(new BezierLine(new Pose(54, 90), new Pose(41.758, 61.439)))
|
||||
.setLinearHeadingInterpolation(Math.toRadians(144), Math.toRadians(180))
|
||||
.build();
|
||||
|
||||
grabSet2Path = follower.pathBuilder()
|
||||
.addPath(new BezierLine(set2DrivePose, set2PickPose))
|
||||
.setTangentHeadingInterpolation()
|
||||
.addPath(new BezierLine(new Pose(41.758, 61.439), new Pose(16, 59.830)))
|
||||
.setLinearHeadingInterpolation(Math.toRadians(180), Math.toRadians(180))
|
||||
.build();
|
||||
|
||||
scoreSet2Path = follower.pathBuilder()
|
||||
.addPath(new BezierCurve(set2PickPose, set2ScoreControl, set2ScorePose))
|
||||
.setLinearHeadingInterpolation(set2PickPose.getHeading(), set2ScorePose.getHeading())
|
||||
.addPath(new BezierCurve(new Pose(16, 59.830), new Pose(55.542, 82.280), new Pose(54, 90)))
|
||||
.setLinearHeadingInterpolation(Math.toRadians(180), Math.toRadians(144))
|
||||
.build();
|
||||
|
||||
grabGate1Path = follower.pathBuilder()
|
||||
.addPath(new BezierCurve(set2ScorePose, gate1PickControl, gate1PickPose))
|
||||
.setLinearHeadingInterpolation(set2ScorePose.getHeading(), gate1PickPose.getHeading())
|
||||
.addPath(new BezierCurve(new Pose(54, 90), new Pose(40.119, 55.595), new Pose(12, 58.3)))
|
||||
.setLinearHeadingInterpolation(Math.toRadians(144), Math.toRadians(138))
|
||||
.build();
|
||||
|
||||
scoreGate1Path = follower.pathBuilder()
|
||||
.addPath(new BezierCurve(gate1PickPose, gate1ScoreControl, gate1ScorePose))
|
||||
.setLinearHeadingInterpolation(gate1PickPose.getHeading(), gate1ScorePose.getHeading())
|
||||
.addPath(new BezierCurve(new Pose(12, 58.3), new Pose(41.918, 62.187), new Pose(54, 90)))
|
||||
.setLinearHeadingInterpolation(Math.toRadians(138), Math.toRadians(144))
|
||||
.build();
|
||||
|
||||
grabGate2Path = follower.pathBuilder()
|
||||
.addPath(new BezierCurve(gate1ScorePose, gate2PickControl, gate2PickPose))
|
||||
.setLinearHeadingInterpolation(gate1ScorePose.getHeading(), gate2PickPose.getHeading())
|
||||
.addPath(new BezierCurve(new Pose(54, 90), new Pose(42.081, 61.914), new Pose(12, 58.3)))
|
||||
.setLinearHeadingInterpolation(Math.toRadians(144), Math.toRadians(138))
|
||||
.build();
|
||||
|
||||
scoreGate2Path = follower.pathBuilder()
|
||||
.addPath(new BezierCurve(gate2PickPose, gate2ScoreControl, gate2ScorePose))
|
||||
.setLinearHeadingInterpolation(gate2PickPose.getHeading(), gate2ScorePose.getHeading())
|
||||
.addPath(new BezierCurve(new Pose(12, 58.3), new Pose(44, 62), new Pose(54, 90)))
|
||||
.setLinearHeadingInterpolation(Math.toRadians(138), Math.toRadians(144))
|
||||
.build();
|
||||
|
||||
driveToSet3Path = follower.pathBuilder()
|
||||
.addPath(new BezierLine(gate2ScorePose, set3DrivePose))
|
||||
.setLinearHeadingInterpolation(gate2ScorePose.getHeading(), set3DrivePose.getHeading())
|
||||
.addPath(new BezierLine(new Pose(54, 90), new Pose(38.515, 47.156)))
|
||||
.setLinearHeadingInterpolation(Math.toRadians(144), Math.toRadians(220))
|
||||
.build();
|
||||
|
||||
grabSet3Path = follower.pathBuilder()
|
||||
.addPath(new BezierCurve(set3DrivePose, set3PickControl, set3PickPose))
|
||||
.setLinearHeadingInterpolation(set3DrivePose.getHeading(), set3PickPose.getHeading())
|
||||
.addPath(new BezierCurve(new Pose(38.515, 47.156), new Pose(29.622, 37.842), new Pose(12, 36)))
|
||||
.setLinearHeadingInterpolation(Math.toRadians(220), Math.toRadians(185))
|
||||
.build();
|
||||
|
||||
scoreSet3Path = follower.pathBuilder()
|
||||
.addPath(new BezierCurve(set3PickPose, set3ScoreControl, set3ScorePose))
|
||||
.setLinearHeadingInterpolation(set3PickPose.getHeading(), set3ScorePose.getHeading())
|
||||
.addPath(new BezierCurve(new Pose(12, 36), new Pose(9.594, 52.541), new Pose(54, 90)))
|
||||
.setLinearHeadingInterpolation(Math.toRadians(185), Math.toRadians(144))
|
||||
.build();
|
||||
|
||||
driveToSet1Path = follower.pathBuilder()
|
||||
.addPath(new BezierLine(set3ScorePose, set1DrivePose))
|
||||
.setLinearHeadingInterpolation(set3ScorePose.getHeading(), set1DrivePose.getHeading())
|
||||
.addPath(new BezierLine(new Pose(54, 90), new Pose(39, 84)))
|
||||
.setLinearHeadingInterpolation(Math.toRadians(144), Math.toRadians(180))
|
||||
.build();
|
||||
|
||||
grabSet1Path = follower.pathBuilder()
|
||||
.addPath(new BezierCurve(set1DrivePose, set1PickControl, set1PickPose))
|
||||
.setLinearHeadingInterpolation(set1DrivePose.getHeading(), set1PickPose.getHeading())
|
||||
.addPath(new BezierCurve(new Pose(39, 84), new Pose(14.863, 77.692), new Pose(29.689, 106.279)))
|
||||
.setLinearHeadingInterpolation(Math.toRadians(180), Math.toRadians(144))
|
||||
.build();
|
||||
|
||||
scoreSet1Path = follower.pathBuilder()
|
||||
.addPath(new BezierLine(set1PickPose, set1ScorePose))
|
||||
.setLinearHeadingInterpolation(set1PickPose.getHeading(), set1ScorePose.getHeading())
|
||||
.addPath(new BezierLine(new Pose(29.689, 106.279), new Pose(44, 100)))
|
||||
.setLinearHeadingInterpolation(Math.toRadians(144), Math.toRadians(148))
|
||||
.build();
|
||||
|
||||
parkPath = follower.pathBuilder()
|
||||
.addPath(new BezierLine(set1ScorePose, parkTargetPose))
|
||||
.setConstantHeadingInterpolation(set1ScorePose.getHeading())
|
||||
.addPath(new BezierLine(new Pose(44, 100), new Pose(36.219, 93.170)))
|
||||
.setConstantHeadingInterpolation(Math.toRadians(148))
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -239,74 +190,54 @@ public class Auton {
|
||||
startPose = new Pose(85, 9, Math.toRadians(90));
|
||||
follower.setStartingPose(startPose);
|
||||
|
||||
Pose scorePosePreload = new Pose(85, 15, Math.toRadians(62));
|
||||
Pose scorePoseGeneric = new Pose(85, 15, Math.toRadians(62));
|
||||
Pose set1Inter = new Pose(100, 36, Math.toRadians(0));
|
||||
Pose set1Pick = new Pose(127, 36, Math.toRadians(0));
|
||||
Pose set2Inter = new Pose(103, 60, Math.toRadians(0));
|
||||
Pose set2Pick = new Pose(128, 63, Math.toRadians(0));
|
||||
Pose set2Control1 = new Pose(126.289, 56.837);
|
||||
Pose set2Control2 = new Pose(118.694, 62.677);
|
||||
Pose scoreSet1Control = new Pose(107.379, 19.900);
|
||||
|
||||
// Corner Poses
|
||||
Pose cornerInter = new Pose(134.556, 24.561, Math.toRadians(270));
|
||||
Pose cornerInterControl = new Pose(106.843, 26.830);
|
||||
Pose cornerArtifact1 = new Pose(131.402, 18.008, Math.toRadians(315));
|
||||
Pose cornerArtifact1Control = new Pose(132.003, 24.364);
|
||||
Pose cornerArtifact2 = new Pose(133.449, 13.380, Math.toRadians(340));
|
||||
Pose cornerArtifact3 = new Pose(134.288, 8.993, Math.toRadians(340));
|
||||
Pose parkPose = new Pose(89.386, 19.545, Math.toRadians(45));
|
||||
|
||||
scorePreloadPath = follower.pathBuilder()
|
||||
.addPath(new BezierLine(startPose, scorePosePreload))
|
||||
.setLinearHeadingInterpolation(startPose.getHeading(), Math.toRadians(62))
|
||||
.addPath(new BezierLine(new Pose(85, 9), new Pose(85, 15)))
|
||||
.setLinearHeadingInterpolation(Math.toRadians(90), Math.toRadians(62))
|
||||
.build();
|
||||
|
||||
grabSet1Path = follower.pathBuilder()
|
||||
.addPath(new BezierLine(scorePosePreload, set1Inter))
|
||||
.addPath(new BezierLine(new Pose(85, 15), new Pose(100, 36)))
|
||||
.setLinearHeadingInterpolation(Math.toRadians(62), Math.toRadians(0))
|
||||
.addPath(new BezierLine(set1Inter, set1Pick))
|
||||
.addPath(new BezierLine(new Pose(100, 36), new Pose(127, 36)))
|
||||
.setConstantHeadingInterpolation(Math.toRadians(0))
|
||||
.build();
|
||||
|
||||
scoreSet1Path = follower.pathBuilder()
|
||||
.addPath(new BezierCurve(set1Pick, scoreSet1Control, scorePoseGeneric))
|
||||
.addPath(new BezierCurve(new Pose(127, 36), new Pose(107.379, 19.900), new Pose(85, 15)))
|
||||
.setLinearHeadingInterpolation(Math.toRadians(0), Math.toRadians(62))
|
||||
.build();
|
||||
|
||||
grabSet2Path = follower.pathBuilder()
|
||||
.addPath(new BezierLine(scorePoseGeneric, set2Inter))
|
||||
.addPath(new BezierLine(new Pose(85, 15), new Pose(103, 60)))
|
||||
.setLinearHeadingInterpolation(Math.toRadians(62), Math.toRadians(0))
|
||||
.addPath(new BezierCurve(set2Inter, set2Control1, set2Control2, set2Pick))
|
||||
.addPath(new BezierCurve(new Pose(103, 60), new Pose(126.289, 56.837), new Pose(118.694, 62.677), new Pose(128, 63)))
|
||||
.setConstantHeadingInterpolation(Math.toRadians(0))
|
||||
.build();
|
||||
|
||||
scoreSet2Path = follower.pathBuilder()
|
||||
.addPath(new BezierLine(set2Pick, scorePoseGeneric))
|
||||
.addPath(new BezierLine(new Pose(128, 63), new Pose(85, 15)))
|
||||
.setLinearHeadingInterpolation(Math.toRadians(0), Math.toRadians(62))
|
||||
.build();
|
||||
|
||||
// Corner Sequence
|
||||
grabEndGamePath = follower.pathBuilder()
|
||||
.addPath(new BezierCurve(scorePoseGeneric, cornerInterControl, cornerInter))
|
||||
.setLinearHeadingInterpolation(Math.toRadians(62), Math.toRadians(270))
|
||||
.addPath(new BezierCurve(cornerInter, cornerArtifact1Control, cornerArtifact1))
|
||||
.setLinearHeadingInterpolation(Math.toRadians(270), Math.toRadians(315))
|
||||
.addPath(new BezierLine(cornerArtifact1, cornerArtifact2))
|
||||
.setLinearHeadingInterpolation(Math.toRadians(315), Math.toRadians(340))
|
||||
.addPath(new BezierLine(cornerArtifact2, cornerArtifact3))
|
||||
.setConstantHeadingInterpolation(Math.toRadians(340))
|
||||
.addPath(new BezierCurve(new Pose(85, 15), new Pose(106.843, 26.830), new Pose(133.600, 8)))
|
||||
.setLinearHeadingInterpolation(Math.toRadians(62), Math.toRadians(0))
|
||||
.build();
|
||||
|
||||
scoreEndGamePath = follower.pathBuilder()
|
||||
.addPath(new BezierLine(cornerArtifact3, scorePoseGeneric))
|
||||
.setLinearHeadingInterpolation(Math.toRadians(340), Math.toRadians(62))
|
||||
.addPath(new BezierLine(new Pose(133.600, 8), new Pose(85, 15)))
|
||||
.setLinearHeadingInterpolation(Math.toRadians(0), Math.toRadians(62))
|
||||
.build();
|
||||
|
||||
parkPath = follower.pathBuilder()
|
||||
.addPath(new BezierLine(scorePoseGeneric, parkPose))
|
||||
.setLinearHeadingInterpolation(Math.toRadians(62), Math.toRadians(45))
|
||||
.addPath(new BezierCurve(new Pose(85, 15), new Pose(106.819, 26.706), new Pose(133.600, 27)))
|
||||
.setLinearHeadingInterpolation(Math.toRadians(45), Math.toRadians(0))
|
||||
.addPath(new BezierLine(new Pose(133.600, 27), new Pose(133.561, 17.195)))
|
||||
.setConstantHeadingInterpolation(Math.toRadians(0))
|
||||
.addPath(new BezierLine(new Pose(133.561, 17.195), new Pose(85, 15)))
|
||||
.setLinearHeadingInterpolation(Math.toRadians(0), Math.toRadians(45))
|
||||
.addPath(new BezierLine(new Pose(85, 15), new Pose(89.386, 19.545)))
|
||||
.setConstantHeadingInterpolation(Math.toRadians(45))
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -319,110 +250,82 @@ public class Auton {
|
||||
|
||||
@Override
|
||||
public void buildPaths() {
|
||||
startPose = new Pose(112.5, 137, Math.toRadians(0));
|
||||
startPose = new Pose(123, 124, Math.toRadians(36.5));
|
||||
follower.setStartingPose(startPose);
|
||||
|
||||
// Waypoints
|
||||
Pose preloadScorePose = new Pose(90, 90, Math.toRadians(36));
|
||||
Pose set2DrivePose = new Pose(105, 60, Math.toRadians(0));
|
||||
Pose set2PickPose = new Pose(130, 60, Math.toRadians(0)); // tangential
|
||||
Pose set2ScorePose = new Pose(90, 90, Math.toRadians(36));
|
||||
Pose gate1PickPose = new Pose(133.348, 61.079, Math.toRadians(40));
|
||||
Pose gate1ScorePose = new Pose(90, 90, Math.toRadians(36));
|
||||
Pose gate2PickPose = new Pose(133.348, 61.079, Math.toRadians(40));
|
||||
Pose gate2ScorePose = new Pose(90, 90, Math.toRadians(36));
|
||||
Pose set3DrivePose = new Pose(105.485, 47.156, Math.toRadians(-40));
|
||||
Pose set3PickPose = new Pose(127.581, 35.945, Math.toRadians(-5));
|
||||
Pose set3ScorePose = new Pose(90, 90, Math.toRadians(36));
|
||||
Pose set1DrivePose = new Pose(105, 84, Math.toRadians(0));
|
||||
Pose set1PickPose = new Pose(114.311, 106.279, Math.toRadians(36));
|
||||
Pose set1ScorePose = new Pose(100, 100, Math.toRadians(32));
|
||||
Pose parkTargetPose = new Pose(107.781, 93.170, Math.toRadians(32));
|
||||
|
||||
// Controls
|
||||
Pose preloadControl = new Pose(116.600, 115.541);
|
||||
Pose set2ScoreControl = new Pose(93.614, 78.923);
|
||||
Pose gate1PickControl = new Pose(103.881, 55.595);
|
||||
Pose gate1ScoreControl = new Pose(102.082, 62.187);
|
||||
Pose gate2PickControl = new Pose(101.919, 61.914);
|
||||
Pose gate2ScoreControl = new Pose(101.682, 61.514);
|
||||
Pose set3PickControl = new Pose(114.378, 37.842);
|
||||
Pose set3ScoreControl = new Pose(134.406, 52.541);
|
||||
Pose set1PickControl = new Pose(129.137, 77.692);
|
||||
|
||||
scorePreloadPath = follower.pathBuilder()
|
||||
.addPath(new BezierCurve(startPose, preloadControl, preloadScorePose))
|
||||
.setLinearHeadingInterpolation(startPose.getHeading(), preloadScorePose.getHeading())
|
||||
.addPath(new BezierLine(new Pose(123, 124), new Pose(90, 90)))
|
||||
.setLinearHeadingInterpolation(Math.toRadians(36.5), Math.toRadians(36))
|
||||
.build();
|
||||
|
||||
driveToSet2Path = follower.pathBuilder()
|
||||
.addPath(new BezierLine(preloadScorePose, set2DrivePose))
|
||||
.setLinearHeadingInterpolation(preloadScorePose.getHeading(), set2DrivePose.getHeading())
|
||||
.addPath(new BezierLine(new Pose(90, 90), new Pose(102.242, 61.439)))
|
||||
.setLinearHeadingInterpolation(Math.toRadians(36), Math.toRadians(0))
|
||||
.build();
|
||||
|
||||
grabSet2Path = follower.pathBuilder()
|
||||
.addPath(new BezierLine(set2DrivePose, set2PickPose))
|
||||
.setTangentHeadingInterpolation()
|
||||
.addPath(new BezierLine(new Pose(102.242, 61.439), new Pose(128, 59.830)))
|
||||
.setLinearHeadingInterpolation(Math.toRadians(0), Math.toRadians(0))
|
||||
.build();
|
||||
|
||||
scoreSet2Path = follower.pathBuilder()
|
||||
.addPath(new BezierCurve(set2PickPose, set2ScoreControl, set2ScorePose))
|
||||
.setLinearHeadingInterpolation(set2PickPose.getHeading(), set2ScorePose.getHeading())
|
||||
.addPath(new BezierCurve(new Pose(128, 59.830), new Pose(88.458, 82.280), new Pose(90, 90)))
|
||||
.setLinearHeadingInterpolation(Math.toRadians(0), Math.toRadians(36))
|
||||
.build();
|
||||
|
||||
grabGate1Path = follower.pathBuilder()
|
||||
.addPath(new BezierCurve(set2ScorePose, gate1PickControl, gate1PickPose))
|
||||
.setLinearHeadingInterpolation(set2ScorePose.getHeading(), gate1PickPose.getHeading())
|
||||
.addPath(new BezierCurve(new Pose(90, 90), new Pose(103.881, 55.595), new Pose(132, 58.3)))
|
||||
.setLinearHeadingInterpolation(Math.toRadians(36), Math.toRadians(42))
|
||||
.build();
|
||||
|
||||
scoreGate1Path = follower.pathBuilder()
|
||||
.addPath(new BezierCurve(gate1PickPose, gate1ScoreControl, gate1ScorePose))
|
||||
.setLinearHeadingInterpolation(gate1PickPose.getHeading(), gate1ScorePose.getHeading())
|
||||
.addPath(new BezierCurve(new Pose(132, 58.3), new Pose(102.082, 62.187), new Pose(90, 90)))
|
||||
.setLinearHeadingInterpolation(Math.toRadians(42), Math.toRadians(36))
|
||||
.build();
|
||||
|
||||
grabGate2Path = follower.pathBuilder()
|
||||
.addPath(new BezierCurve(gate1ScorePose, gate2PickControl, gate2PickPose))
|
||||
.setLinearHeadingInterpolation(gate1ScorePose.getHeading(), gate2PickPose.getHeading())
|
||||
.addPath(new BezierCurve(new Pose(90, 90), new Pose(101.919, 61.914), new Pose(132, 58.3)))
|
||||
.setLinearHeadingInterpolation(Math.toRadians(36), Math.toRadians(42))
|
||||
.build();
|
||||
|
||||
scoreGate2Path = follower.pathBuilder()
|
||||
.addPath(new BezierCurve(gate2PickPose, gate2ScoreControl, gate2ScorePose))
|
||||
.setLinearHeadingInterpolation(gate2PickPose.getHeading(), gate2ScorePose.getHeading())
|
||||
.addPath(new BezierCurve(new Pose(132, 58.3), new Pose(100, 62), new Pose(90, 90)))
|
||||
.setLinearHeadingInterpolation(Math.toRadians(42), Math.toRadians(36))
|
||||
.build();
|
||||
|
||||
driveToSet3Path = follower.pathBuilder()
|
||||
.addPath(new BezierLine(gate2ScorePose, set3DrivePose))
|
||||
.setLinearHeadingInterpolation(gate2ScorePose.getHeading(), set3DrivePose.getHeading())
|
||||
.addPath(new BezierLine(new Pose(90, 90), new Pose(105.485, 47.156)))
|
||||
.setLinearHeadingInterpolation(Math.toRadians(36), Math.toRadians(-40))
|
||||
.build();
|
||||
|
||||
grabSet3Path = follower.pathBuilder()
|
||||
.addPath(new BezierCurve(set3DrivePose, set3PickControl, set3PickPose))
|
||||
.setLinearHeadingInterpolation(set3DrivePose.getHeading(), set3PickPose.getHeading())
|
||||
.addPath(new BezierCurve(new Pose(105.485, 47.156), new Pose(114.378, 37.842), new Pose(132, 36)))
|
||||
.setLinearHeadingInterpolation(Math.toRadians(-40), Math.toRadians(-5))
|
||||
.build();
|
||||
|
||||
scoreSet3Path = follower.pathBuilder()
|
||||
.addPath(new BezierCurve(set3PickPose, set3ScoreControl, set3ScorePose))
|
||||
.setLinearHeadingInterpolation(set3PickPose.getHeading(), set3ScorePose.getHeading())
|
||||
.addPath(new BezierCurve(new Pose(132, 36), new Pose(134.406, 52.541), new Pose(90, 90)))
|
||||
.setLinearHeadingInterpolation(Math.toRadians(-5), Math.toRadians(36))
|
||||
.build();
|
||||
|
||||
driveToSet1Path = follower.pathBuilder()
|
||||
.addPath(new BezierLine(set3ScorePose, set1DrivePose))
|
||||
.setLinearHeadingInterpolation(set3ScorePose.getHeading(), set1DrivePose.getHeading())
|
||||
.addPath(new BezierLine(new Pose(90, 90), new Pose(105, 84)))
|
||||
.setLinearHeadingInterpolation(Math.toRadians(36), Math.toRadians(0))
|
||||
.build();
|
||||
|
||||
grabSet1Path = follower.pathBuilder()
|
||||
.addPath(new BezierCurve(set1DrivePose, set1PickControl, set1PickPose))
|
||||
.setLinearHeadingInterpolation(set1DrivePose.getHeading(), set1PickPose.getHeading())
|
||||
.addPath(new BezierCurve(new Pose(105, 84), new Pose(129.137, 77.692), new Pose(114.311, 106.279)))
|
||||
.setLinearHeadingInterpolation(Math.toRadians(0), Math.toRadians(36))
|
||||
.build();
|
||||
|
||||
scoreSet1Path = follower.pathBuilder()
|
||||
.addPath(new BezierLine(set1PickPose, set1ScorePose))
|
||||
.setLinearHeadingInterpolation(set1PickPose.getHeading(), set1ScorePose.getHeading())
|
||||
.addPath(new BezierLine(new Pose(114.311, 106.279), new Pose(100, 100)))
|
||||
.setLinearHeadingInterpolation(Math.toRadians(36), Math.toRadians(32))
|
||||
.build();
|
||||
|
||||
parkPath = follower.pathBuilder()
|
||||
.addPath(new BezierLine(set1ScorePose, parkTargetPose))
|
||||
.setConstantHeadingInterpolation(set1ScorePose.getHeading())
|
||||
.addPath(new BezierLine(new Pose(100, 100), new Pose(107.781, 93.170)))
|
||||
.setConstantHeadingInterpolation(Math.toRadians(32))
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -442,7 +345,7 @@ public class Auton {
|
||||
protected final boolean isNet;
|
||||
protected final boolean useTimer;
|
||||
|
||||
public static double timerTimeout = 4;
|
||||
public static double timerTimeout = 2.8;
|
||||
public static double gateWaitTime = 3.0;
|
||||
|
||||
protected Pose startPose;
|
||||
@@ -531,19 +434,22 @@ public class Auton {
|
||||
telemetry.update();
|
||||
}
|
||||
|
||||
follower.update();
|
||||
|
||||
turretHw.resetTurret();
|
||||
|
||||
waitForStart();
|
||||
systems.update(allianceTarget, follower.getPose());
|
||||
systems.update(allianceTarget, follower.getPose(), new Vector(0, 0));
|
||||
opmodeTimer.resetTimer();
|
||||
setPathState(PathState.DRIVE_TO_SCORE_PRELOAD);
|
||||
|
||||
while (opModeIsActive()) {
|
||||
|
||||
for (LynxModule hub : allHubs) {
|
||||
hub.clearBulkCache();
|
||||
}
|
||||
follower.update();
|
||||
statePathUpdate();
|
||||
systems.update(allianceTarget, follower.getPose());
|
||||
systems.update(allianceTarget, follower.getPose(), follower.getVelocity());
|
||||
|
||||
telemetry.addData("Path State", pathState);
|
||||
telemetry.addData("System State", systems.getCurrentState());
|
||||
@@ -630,7 +536,7 @@ public class Auton {
|
||||
if (!follower.isBusy()) {
|
||||
systems.setAutonState(pedroStateMachine.AutonState.SCORING);
|
||||
if (checkScoringCondition()) {
|
||||
setPathState(PathState.DRIVE_TO_PARK);
|
||||
setPathState(PathState.DRIVE_TO_ENDGAME_COLLECTION);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -137,7 +137,7 @@ public abstract class TimeAuton extends LinearOpMode {
|
||||
timer.reset();
|
||||
while(opModeIsActive() && timer.seconds() < 2.0) {
|
||||
updateSystems();
|
||||
if(turret.isTurretReady()) break;
|
||||
if(turret.isTurretReady(true)) break;
|
||||
|
||||
}
|
||||
|
||||
@@ -167,13 +167,13 @@ public abstract class TimeAuton extends LinearOpMode {
|
||||
AutoTransfer.updatePose(currentPose);
|
||||
|
||||
// Update Turret with current Pose
|
||||
turret.updateAuton(alliance, currentPose, 0.2);
|
||||
turret.updateAuton(alliance, currentPose, follower.getVelocity(), 0.2);
|
||||
|
||||
transfer.updateTurretReady(turret.isTurretReady());
|
||||
transfer.updateTurretReady(turret.isTurretReady(true));
|
||||
transfer.update();
|
||||
|
||||
// Telemetry for debugging
|
||||
telemetry.addData("Turret Ready", turret.isTurretReady());
|
||||
telemetry.addData("Turret Ready", turret.isTurretReady(false));
|
||||
telemetry.addData("Transfer State", transfer.getTransferState());
|
||||
telemetry.update();
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.firstinspires.ftc.teamcode.auton;
|
||||
|
||||
import com.pedropathing.geometry.Pose;
|
||||
import com.pedropathing.math.Vector;
|
||||
|
||||
import org.firstinspires.ftc.teamcode.Hware.hwMap;
|
||||
import org.firstinspires.ftc.teamcode.subsystems.DriveTrain; // Unused but kept for reference
|
||||
@@ -12,6 +13,7 @@ import org.firstinspires.ftc.teamcode.subsystems.TransferSys.TransferState;
|
||||
import org.firstinspires.ftc.teamcode.subsystems.Intake.IntakeState;
|
||||
|
||||
import org.firstinspires.ftc.teamcode.util.AutoTransfer;
|
||||
import org.firstinspires.ftc.teamcode.teleOp.Constants;
|
||||
|
||||
public class pedroStateMachine {
|
||||
|
||||
@@ -27,6 +29,10 @@ public class pedroStateMachine {
|
||||
private final Turret m_turret;
|
||||
|
||||
|
||||
private boolean PIDFShooting = false;
|
||||
private boolean lastPIDFShooting = false;
|
||||
|
||||
|
||||
|
||||
private int alliance = 0;
|
||||
|
||||
@@ -35,6 +41,9 @@ public class pedroStateMachine {
|
||||
this.m_transfer = new TransferSys(h_transfer);
|
||||
this.m_turret = new Turret(h_turret);
|
||||
|
||||
m_turret.setPIDF(Constants.TurretConstants.PIDF_NORMAL);
|
||||
m_turret.setLaunching(false);
|
||||
|
||||
setAutonState(AutonState.IDLE);
|
||||
AutoTransfer.reset();
|
||||
}
|
||||
@@ -57,26 +66,28 @@ public class pedroStateMachine {
|
||||
switch (oldState) {
|
||||
case INTAKING:
|
||||
m_intake.setIntakeState(IntakeState.IDLE);
|
||||
// Ensure gate is closed when we stop intaking to hold rings
|
||||
m_transfer.setTransferState(TransferState.IDLE);
|
||||
break;
|
||||
case SCORING:
|
||||
m_transfer.setTransferState(TransferState.IDLE);
|
||||
m_turret.setTurretState(Turret.TurretState.IDLE);
|
||||
m_intake.setIntakeState(Intake.IntakeState.IDLE);
|
||||
PIDFShooting = false;
|
||||
m_turret.setLaunching(false);
|
||||
m_turret.setPIDF(Constants.TurretConstants.PIDF_NORMAL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void handleStateEntry(AutonState newState) {
|
||||
switch (newState) {
|
||||
case INTAKING:
|
||||
m_intake.setIntakeState(IntakeState.INTAKE);
|
||||
m_turret.setTurretState(TurretState.INTAKING); // Optional: position turret for intake stability
|
||||
m_transfer.closeLimiter(); // Ensure rings don't fly out back
|
||||
m_turret.setTurretState(TurretState.INTAKING);
|
||||
m_transfer.closeLimiter();
|
||||
break;
|
||||
case SCORING:
|
||||
m_intake.setIntakeState(IntakeState.LAUNCH); // Feed rings
|
||||
m_turret.setTurretState(TurretState.LAUNCH);
|
||||
m_transfer.setTransferState(TransferState.LAUNCHING);
|
||||
break;
|
||||
@@ -88,15 +99,32 @@ public class pedroStateMachine {
|
||||
}
|
||||
}
|
||||
|
||||
public void update(int allianceTarget, Pose currentPose) {
|
||||
m_turret.updateAuton(allianceTarget, currentPose, 0.2);
|
||||
public void update(int allianceTarget, Pose currentPose, Vector currentVelocity) {
|
||||
m_turret.updateAuton(allianceTarget, currentPose, currentVelocity, 0.2);
|
||||
|
||||
if (currentState == AutonState.SCORING) {
|
||||
m_transfer.updateTurretReady(m_turret.hasReachedVelocity());
|
||||
|
||||
if (m_turret.hasReachedVelocity() || PIDFShooting) {
|
||||
m_intake.setIntakeState(IntakeState.LAUNCH);
|
||||
PIDFShooting = true;
|
||||
}
|
||||
} else {
|
||||
PIDFShooting = false;
|
||||
}
|
||||
|
||||
m_transfer.update();
|
||||
if (PIDFShooting != lastPIDFShooting) {
|
||||
if (PIDFShooting) {
|
||||
m_turret.setLaunching(true); // Freeze Vision Offsets
|
||||
m_turret.setPIDF(Constants.TurretConstants.PIDF_Shooting); // High-power recovery PID
|
||||
} else {
|
||||
m_turret.setLaunching(false); // Resume Vision Tracking
|
||||
m_turret.setPIDF(Constants.TurretConstants.PIDF_NORMAL); // Precise tracking PID
|
||||
}
|
||||
}
|
||||
lastPIDFShooting = PIDFShooting;
|
||||
|
||||
m_transfer.update();
|
||||
|
||||
if (currentState == AutonState.SCORING) {
|
||||
if (m_transfer.getTransferState() != TransferSys.TransferState.LAUNCHING) {
|
||||
|
||||
@@ -25,7 +25,7 @@ public class Constants {
|
||||
.lateralZeroPowerAcceleration(-76.57271150137258);
|
||||
|
||||
public static MecanumConstants driveConstants = new MecanumConstants()
|
||||
.maxPower(0.8)
|
||||
.maxPower(0.7)
|
||||
.xVelocity(68.10320673181904)
|
||||
.yVelocity(57.52038399624941)
|
||||
.rightFrontMotorName(DriveConstants.FRONT_RIGHT_MOTOR)
|
||||
@@ -41,15 +41,15 @@ public class Constants {
|
||||
|
||||
|
||||
public static ThreeWheelConstants localizerConstants = new ThreeWheelConstants()
|
||||
.forwardTicksToInches(0.001978956)
|
||||
.strafeTicksToInches(0.001978956)
|
||||
.forwardTicksToInches(0.0020041908950982315)
|
||||
.strafeTicksToInches(0.002004094712407555)
|
||||
.turnTicksToInches(0.0022824233082645137)
|
||||
.leftPodY(3.75)
|
||||
.rightPodY(-3.25)
|
||||
.strafePodX(-6.25)
|
||||
.leftEncoder_HardwareMapName("intake")
|
||||
.rightEncoder_HardwareMapName("fl")
|
||||
.strafeEncoder_HardwareMapName("bl")
|
||||
.strafeEncoder_HardwareMapName("fr")
|
||||
.leftEncoderDirection(Encoder.FORWARD)
|
||||
.rightEncoderDirection(Encoder.FORWARD)
|
||||
.strafeEncoderDirection(Encoder.FORWARD);
|
||||
|
||||
@@ -40,7 +40,7 @@ public class DriveTrain {
|
||||
public enum DriveState {
|
||||
NORMAL, TURBO, PRECISION, STOP
|
||||
}
|
||||
private DriveState currentState = DriveState.NORMAL;
|
||||
private DriveState currentState = DriveState.TURBO;
|
||||
private double speedMultiplier = 1.0;
|
||||
|
||||
public DriveTrain(hwMap.DriveHwMap hardware) {
|
||||
@@ -59,8 +59,8 @@ public class DriveTrain {
|
||||
if(dt == 0) dt = 0.001;
|
||||
lastLoopTime = currentTime;
|
||||
|
||||
double currentFwd = h_driveTrain.backRightMotor.getCurrentPosition();
|
||||
double currentStrafe = h_driveTrain.frontLeftMotor.getCurrentPosition();
|
||||
double currentFwd = h_driveTrain.frontLeftMotor.getCurrentPosition();
|
||||
double currentStrafe = h_driveTrain.frontRightMotor.getCurrentPosition();
|
||||
double currentHeading = getHeadingDegrees();
|
||||
|
||||
// 2. Calculate Errors
|
||||
@@ -72,8 +72,6 @@ public class DriveTrain {
|
||||
while (errorTurn > 180) errorTurn -= 360;
|
||||
while (errorTurn < -180) errorTurn += 360;
|
||||
|
||||
// 3. PID Calculations
|
||||
|
||||
// Forward
|
||||
sumFwd += errorForward * dt;
|
||||
double dFwd = (errorForward - lastFwdErr) / dt;
|
||||
|
||||
@@ -1,76 +1,50 @@
|
||||
package org.firstinspires.ftc.teamcode.subsystems;
|
||||
|
||||
import org.firstinspires.ftc.teamcode.Hware.hwMap;
|
||||
import org.firstinspires.ftc.teamcode.Prism.Color;
|
||||
import org.firstinspires.ftc.teamcode.Prism.GoBildaPrismDriver.LayerHeight;
|
||||
import org.firstinspires.ftc.teamcode.Prism.PrismAnimations;
|
||||
import org.firstinspires.ftc.teamcode.teleOp.Constants;
|
||||
|
||||
public class LED {
|
||||
private final hwMap.LedHwMap hardware;
|
||||
|
||||
// Track states to prevent spamming the I2C bus
|
||||
private int currentLed1State = -1;
|
||||
private int currentLed2State = -1;
|
||||
|
||||
// Reusable animations for efficiency
|
||||
private final PrismAnimations.Solid solidRed = new PrismAnimations.Solid(Color.RED);
|
||||
private final PrismAnimations.Solid solidOrange = new PrismAnimations.Solid(Color.ORANGE);
|
||||
private final PrismAnimations.Solid solidGreen = new PrismAnimations.Solid(Color.GREEN);
|
||||
private final PrismAnimations.Solid solidBlue = new PrismAnimations.Solid(Color.BLUE);
|
||||
private final PrismAnimations.Solid solidPurple = new PrismAnimations.Solid(Color.PURPLE); // or MAGENTA if PURPLE is missing
|
||||
private int currentLedState = -1;
|
||||
|
||||
public LED(hwMap.LedHwMap hardware) {
|
||||
this.hardware = hardware;
|
||||
|
||||
solidRed.setBrightness(50);
|
||||
solidOrange.setBrightness(50);
|
||||
solidGreen.setBrightness(50);
|
||||
solidBlue.setBrightness(50);
|
||||
solidPurple.setBrightness(50);
|
||||
turnOn();
|
||||
}
|
||||
|
||||
public void update(boolean isScoring, boolean isTurretReady, boolean hasTarget, boolean isAnchorActive) {
|
||||
/*
|
||||
int newLed1State = 0;
|
||||
if (isScoring) {
|
||||
if (isTurretReady) {
|
||||
newLed1State = 2;
|
||||
} else {
|
||||
newLed1State = 1;
|
||||
}
|
||||
public void update(boolean isTurretLocked, boolean isFlywheelUpToSpeed) {
|
||||
int newLedState = 0;
|
||||
|
||||
if (isTurretLocked && isFlywheelUpToSpeed) {
|
||||
newLedState = 1;
|
||||
} else if (isTurretLocked) {
|
||||
newLedState = 2;
|
||||
} else if (isFlywheelUpToSpeed) {
|
||||
newLedState = 3;
|
||||
}
|
||||
|
||||
if (newLed1State != currentLed1State) {
|
||||
if (newLed1State == 0) {
|
||||
hardware.led1.insertAndUpdateAnimation(LayerHeight.LAYER_0, solidRed);
|
||||
} else if (newLed1State == 1) {
|
||||
hardware.led1.insertAndUpdateAnimation(LayerHeight.LAYER_0, solidOrange);
|
||||
} else if (newLed1State == 2) {
|
||||
hardware.led1.insertAndUpdateAnimation(LayerHeight.LAYER_0, solidGreen);
|
||||
if (newLedState != currentLedState) {
|
||||
if (newLedState == 0) {
|
||||
hardware.setLedPos(Constants.LEDConstants.COLOR_RED);
|
||||
} else if (newLedState == 1) {
|
||||
hardware.setLedPos(Constants.LEDConstants.COLOR_GREEN);
|
||||
} else if (newLedState == 2) {
|
||||
hardware.setLedPos(Constants.LEDConstants.COLOR_ORANGE);
|
||||
} else if (newLedState == 3) {
|
||||
hardware.setLedPos(Constants.LEDConstants.COLOR_YELLOW);
|
||||
}
|
||||
currentLed1State = newLed1State;
|
||||
}
|
||||
|
||||
int newLed2State = 0;
|
||||
if (hasTarget && isAnchorActive) {
|
||||
newLed2State = 3;
|
||||
} else if (hasTarget) {
|
||||
newLed2State = 1;
|
||||
} else if (isAnchorActive) {
|
||||
newLed2State = 2;
|
||||
currentLedState = newLedState;
|
||||
}
|
||||
}
|
||||
|
||||
if (newLed2State != currentLed2State) {
|
||||
if (newLed2State == 0) {
|
||||
hardware.led2.insertAndUpdateAnimation(LayerHeight.LAYER_0, solidRed);
|
||||
} else if (newLed2State == 1) {
|
||||
hardware.led2.insertAndUpdateAnimation(LayerHeight.LAYER_0, solidGreen);
|
||||
} else if (newLed2State == 2) {
|
||||
hardware.led2.insertAndUpdateAnimation(LayerHeight.LAYER_0, solidBlue);
|
||||
} else if (newLed2State == 3) {
|
||||
hardware.led2.insertAndUpdateAnimation(LayerHeight.LAYER_0, solidPurple);
|
||||
}
|
||||
currentLed2State = newLed2State;
|
||||
}*/
|
||||
public void turnOff() {
|
||||
hardware.setLedOn(false);
|
||||
currentLedState = -1;
|
||||
}
|
||||
|
||||
public void turnOn() {
|
||||
hardware.setLedOn(true);
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package org.firstinspires.ftc.teamcode.subsystems;
|
||||
|
||||
import com.qualcomm.robotcore.util.ElapsedTime;
|
||||
import org.firstinspires.ftc.teamcode.Hware.hwMap;
|
||||
import org.firstinspires.ftc.teamcode.teleOp.Constants;
|
||||
|
||||
public class TransferSys {
|
||||
private final hwMap.TransferHwMap hardware;
|
||||
@@ -9,7 +10,7 @@ public class TransferSys {
|
||||
private boolean isTurretReady = false;
|
||||
private boolean limiterClosed = true;
|
||||
|
||||
public double launchDuration = 2; // CHANGEABLE TODO
|
||||
public double launchDuration = Constants.TransferConstants.launch_duration; // CHANGEABLE TODO
|
||||
|
||||
public enum TransferState {
|
||||
LAUNCHING, // Gate OPEN
|
||||
@@ -94,6 +95,13 @@ public class TransferSys {
|
||||
return limiterClosed;
|
||||
}
|
||||
|
||||
public double getLaunchElapsedTime() {
|
||||
if (currentState == TransferState.LAUNCHING && isLaunchSequenceActive) {
|
||||
return timer.seconds();
|
||||
}
|
||||
return 100.0;
|
||||
}
|
||||
|
||||
public TransferState getTransferState() {
|
||||
return currentState;
|
||||
}
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
package org.firstinspires.ftc.teamcode.subsystems;
|
||||
|
||||
import static org.firstinspires.ftc.teamcode.tuning.allInOne.OFFSET_GAIN;
|
||||
import static org.firstinspires.ftc.teamcode.tuning.allInOne.SERVO_MIN;
|
||||
|
||||
import com.pedropathing.geometry.Pose;
|
||||
import com.qualcomm.hardware.limelightvision.LLResult;
|
||||
import com.qualcomm.robotcore.util.ElapsedTime;
|
||||
import com.qualcomm.robotcore.util.Range;
|
||||
|
||||
import org.firstinspires.ftc.teamcode.Hware.hwMap;
|
||||
import org.firstinspires.ftc.teamcode.teleOp.Constants;
|
||||
|
||||
import com.pedropathing.math.Vector;
|
||||
|
||||
public class Turret {
|
||||
|
||||
private final hwMap.TurretHwMap hardware;
|
||||
@@ -27,13 +27,28 @@ public class Turret {
|
||||
private double targetCorrectionOffsetTicks = 0;
|
||||
private double fusedTargetTicks = 0;
|
||||
public double turretPowerRotation;
|
||||
public static double offsetTicks = 0.0;
|
||||
private double offsetTicks = 0.0;
|
||||
|
||||
public double offsetHood = 0;
|
||||
|
||||
private Pose robotPose;
|
||||
private Vector robotVelocity = new Vector(0, 0); // NEW
|
||||
private double kinematicDistanceOffset = 0.0; // NEW
|
||||
private double kinematicAngularOffsetTicks = 0.0; // NEW
|
||||
|
||||
private double distanceOffset = 0.0;
|
||||
private double visionDistanceOffset = 0.0;
|
||||
|
||||
public double targetTick;
|
||||
|
||||
private final ElapsedTime loopTimer = new ElapsedTime();
|
||||
private final ElapsedTime stateTimer = new ElapsedTime();
|
||||
|
||||
public boolean turretModeHold = false;
|
||||
|
||||
public boolean lastTurretModeHold = false;
|
||||
|
||||
private boolean isLaunching = false;
|
||||
|
||||
public enum TurretState {
|
||||
LAUNCH,
|
||||
@@ -41,21 +56,29 @@ public class Turret {
|
||||
EXTAKE,
|
||||
INTAKING
|
||||
}
|
||||
|
||||
private TurretState currentState = TurretState.IDLE;
|
||||
|
||||
public Turret(hwMap.TurretHwMap hardware) {
|
||||
this.hardware = hardware;
|
||||
offsetTicks = 0; // Reset manual offset on every init
|
||||
targetCorrectionOffsetTicks = 0; // Reset vision correction
|
||||
loopTimer.reset();
|
||||
stateTimer.reset();
|
||||
}
|
||||
|
||||
public void setAlliance(int alliance) {
|
||||
this.alliance = alliance;
|
||||
if (alliance == 2) {
|
||||
hardware.setPipeline(Constants.TurretConstants.LIMELIGHT_PIPELINE_RED_TARGET);
|
||||
} else if(alliance == 1) {
|
||||
hardware.setPipeline(Constants.TurretConstants.LIMELIGHT_PIPELINE_BLUE_TARGET);
|
||||
} else {
|
||||
hardware.setPipeline(0);
|
||||
if (this.alliance != alliance) {
|
||||
this.alliance = alliance;
|
||||
targetCorrectionOffsetTicks = 0; // Reset correction when alliance changes
|
||||
offsetTicks = 0; // Reset manual offset when alliance changes
|
||||
if (alliance == 2) {
|
||||
hardware.setPipeline(Constants.TurretConstants.LIMELIGHT_PIPELINE_RED_TARGET);
|
||||
} else if (alliance == 1) {
|
||||
hardware.setPipeline(Constants.TurretConstants.LIMELIGHT_PIPELINE_BLUE_TARGET);
|
||||
} else {
|
||||
hardware.setPipeline(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,21 +91,24 @@ public class Turret {
|
||||
}
|
||||
|
||||
public void setTurretState(TurretState state) {
|
||||
this.currentState = state;
|
||||
if (this.currentState != state) {
|
||||
this.currentState = state;
|
||||
stateTimer.reset();
|
||||
|
||||
switch (state) {
|
||||
case IDLE:
|
||||
hardware.turretOff();
|
||||
hardware.stopTurretRotation();
|
||||
integralSum = 0;
|
||||
lastError = 0;
|
||||
break;
|
||||
case EXTAKE:
|
||||
hardware.setTurretPower(Constants.TurretConstants.EXTAKE_POWER);
|
||||
break;
|
||||
case INTAKING:
|
||||
hardware.setTurretPower(Constants.TurretConstants.INTAKE_POWER);
|
||||
break;
|
||||
switch (state) {
|
||||
case IDLE:
|
||||
hardware.turretOff();
|
||||
hardware.stopTurretRotation();
|
||||
integralSum = 0;
|
||||
lastError = 0;
|
||||
break;
|
||||
case EXTAKE:
|
||||
hardware.setTurretPower(Constants.TurretConstants.EXTAKE_POWER);
|
||||
break;
|
||||
case INTAKING:
|
||||
hardware.setTurretPower(Constants.TurretConstants.INTAKE_POWER);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,17 +121,17 @@ public class Turret {
|
||||
return hardware.hasTarget();
|
||||
}
|
||||
|
||||
public void update(boolean manualTracking, boolean manualSAM, Pose currentPose) {
|
||||
public void update(boolean manualTracking, boolean manualSAM, Pose currentPose, Vector currentVelocity, double elapsedTime) {
|
||||
double dt = loopTimer.seconds();
|
||||
loopTimer.reset();
|
||||
if (dt < 0.001) dt = 0.001;
|
||||
|
||||
updatePose(currentPose);
|
||||
updatePose(currentPose, currentVelocity);
|
||||
|
||||
double rawTicks = hardware.getTurretRotationPosition();
|
||||
double currentDegrees = rawTicks / Constants.TurretConstants.TICKS_PER_DEGREE;
|
||||
|
||||
distance = getDistance();
|
||||
distance = getDistance() + kinematicDistanceOffset + distanceOffset;
|
||||
|
||||
if (!manualTracking) {
|
||||
calculateHybridTarget(currentPose, currentDegrees, rawTicks);
|
||||
@@ -115,39 +141,93 @@ public class Turret {
|
||||
}
|
||||
|
||||
if (currentState == TurretState.LAUNCH) {
|
||||
handleLaunchLogic();
|
||||
handleLaunchLogic(elapsedTime);
|
||||
} else {
|
||||
idleLaunch();
|
||||
}
|
||||
}
|
||||
|
||||
public void updateAuton(int alliance, Pose currentPose, double offset) {
|
||||
updatePose(currentPose);
|
||||
|
||||
public void idleLaunch() {
|
||||
targetVelocity = 1600;
|
||||
hardware.setTurretVelocity(targetVelocity);
|
||||
|
||||
double calculatedHoodPos = getHoodPOS(65);
|
||||
setHoodPos(calculatedHoodPos);
|
||||
}
|
||||
|
||||
public void updateAuton(int alliance, Pose currentPose, Vector currentVelocity, double offset) {
|
||||
updatePose(currentPose, currentVelocity); // Updated
|
||||
double dt = loopTimer.seconds();
|
||||
loopTimer.reset();
|
||||
if (dt < 0.001) dt = 0.001;
|
||||
|
||||
setAlliance(alliance);
|
||||
|
||||
if (currentState == TurretState.IDLE) {
|
||||
hardware.stopTurretRotation();
|
||||
return;
|
||||
}
|
||||
|
||||
double rawTicks = hardware.getTurretRotationPosition();
|
||||
double currentDegrees = rawTicks / Constants.TurretConstants.TICKS_PER_DEGREE;
|
||||
|
||||
distance = getDistance();
|
||||
distance = getDistance() + kinematicDistanceOffset;
|
||||
|
||||
calculateHybridTarget(currentPose, currentDegrees, rawTicks);
|
||||
runPIDControl(rawTicks, dt);
|
||||
handleLaunchLogic(-offset);
|
||||
handleLaunchLogicOffset(offset);
|
||||
}
|
||||
|
||||
private void handleLaunchLogic() {
|
||||
private void handleLaunchLogic(double elapsedTime) {
|
||||
if (distance > 0) {
|
||||
targetVelocity = getFlywheelVelocity(distance);
|
||||
double baseVelocity = getFlywheelVelocity(distance);
|
||||
double t = stateTimer.seconds();
|
||||
|
||||
double compensation;
|
||||
if (t < Constants.TurretConstants.ARTIFACT_1_WINDOW) {
|
||||
compensation = Constants.TurretConstants.ARTIFACT_1;
|
||||
} else if (t < Constants.TurretConstants.ARTIFACT_2_WINDOW) {
|
||||
compensation = Constants.TurretConstants.ARTIFACT_2;
|
||||
} else {
|
||||
compensation = Constants.TurretConstants.ARTIFACT_3;
|
||||
}
|
||||
|
||||
targetVelocity = baseVelocity + compensation;
|
||||
hardware.setTurretVelocity(targetVelocity);
|
||||
|
||||
double calculatedHoodPos = getHoodPOS(distance);
|
||||
double currentVel = hardware.getFlywheelVelocities()[0];
|
||||
double dropThreshold = targetVelocity * 0.95;
|
||||
double recoilOffset = 0.0;
|
||||
double currentVel = hardware.getFlywheelVelocities()[1];
|
||||
|
||||
recoilOffset = (currentVel - targetVelocity) * 0.000004;
|
||||
double recoilOffset = (currentVel - targetVelocity) * -0.000385;
|
||||
|
||||
setHoodPos(calculatedHoodPos + recoilOffset - 0.03);
|
||||
} else {
|
||||
hardware.setTurretVelocity(0);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleLaunchLogicOffset(double offset) {
|
||||
if (distance > 0) {
|
||||
double baseVelocity = getFlywheelVelocity(distance);
|
||||
double t = stateTimer.seconds();
|
||||
|
||||
double compensation;
|
||||
if (t < Constants.TurretConstants.ARTIFACT_1_WINDOW) {
|
||||
compensation = Constants.TurretConstants.ARTIFACT_1;
|
||||
} else if (t < Constants.TurretConstants.ARTIFACT_2_WINDOW) {
|
||||
compensation = Constants.TurretConstants.ARTIFACT_2;
|
||||
} else {
|
||||
compensation = Constants.TurretConstants.ARTIFACT_3;
|
||||
}
|
||||
|
||||
targetVelocity = baseVelocity + compensation;
|
||||
hardware.setTurretVelocity(targetVelocity);
|
||||
|
||||
double calculatedHoodPos = getHoodPOS(distance);
|
||||
double currentVel = hardware.getFlywheelVelocities()[1];
|
||||
|
||||
double recoilOffset = (currentVel - targetVelocity) * -0.000385;
|
||||
|
||||
setHoodPos(calculatedHoodPos + recoilOffset);
|
||||
} else {
|
||||
@@ -155,36 +235,90 @@ public class Turret {
|
||||
}
|
||||
}
|
||||
|
||||
private void handleLaunchLogic(double offset) {
|
||||
if (distance > 0) {
|
||||
targetVelocity = getFlywheelVelocity(distance);
|
||||
hardware.setTurretVelocity(targetVelocity);
|
||||
|
||||
double calculatedHoodPos = getHoodPOS(distance);
|
||||
double currentVel = hardware.getFlywheelVelocities()[0];
|
||||
double dropThreshold = targetVelocity * 0.95;
|
||||
double recoilOffset = 0.0;
|
||||
|
||||
recoilOffset = (currentVel - targetVelocity) * 0.000004;
|
||||
|
||||
setHoodPos(calculatedHoodPos + recoilOffset);
|
||||
} else {
|
||||
hardware.setTurretVelocity(0);
|
||||
}
|
||||
}
|
||||
|
||||
private void calculateHybridTarget(Pose robotPose, double currentDegrees, double currentTicks) {
|
||||
/*private void calculateHybridTarget(Pose robotPose, double currentDegrees, double currentTicks) {
|
||||
double odoTargetTicks = calculateOdometryTargetTicks(robotPose);
|
||||
LLResult result = hardware.getLimelightResult();
|
||||
|
||||
if (result != null && result.isValid()) {
|
||||
double rawErrorTicks = getErrorTicks(currentDegrees, result, odoTargetTicks);
|
||||
targetCorrectionOffsetTicks = (targetCorrectionOffsetTicks * (1.0 - Constants.TurretConstants.OFFSET_SMOOTHING))
|
||||
+ (rawErrorTicks * Constants.TurretConstants.OFFSET_SMOOTHING);
|
||||
double tx = result.getTx();
|
||||
double visionTargetDegrees = currentDegrees + (tx * Constants.TurretConstants.LL_LOGIC_MULTIPLIER);
|
||||
double finalVisionDegrees = visionTargetDegrees + Constants.TurretConstants.LL_TARGET_OFFSET_DEGREES;
|
||||
double visionTargetTicks = finalVisionDegrees * Constants.TurretConstants.TICKS_PER_DEGREE;
|
||||
|
||||
visionTargetTicks += kinematicAngularOffsetTicks;
|
||||
|
||||
// Shift the vision target by our manual offset so LL doesn't fight it
|
||||
double visionTargetWithManualOffset = visionTargetTicks + offsetTicks;
|
||||
|
||||
double currentFusedTarget = odoTargetTicks + targetCorrectionOffsetTicks;
|
||||
|
||||
double correctionError = visionTargetWithManualOffset - currentFusedTarget;
|
||||
|
||||
// 4. Normalize the error for wrapping (360 degrees)
|
||||
double ticksPerRev = 360.0 * Constants.TurretConstants.TICKS_PER_DEGREE;
|
||||
while (correctionError > (ticksPerRev / 2)) correctionError -= ticksPerRev;
|
||||
while (correctionError < -(ticksPerRev / 2)) correctionError += ticksPerRev;
|
||||
|
||||
// 5. Apply the error to the persistent offset (Bias-Shift)
|
||||
targetCorrectionOffsetTicks += (correctionError * Constants.TurretConstants.OFFSET_SMOOTHING);
|
||||
}
|
||||
|
||||
double rawTarget = odoTargetTicks + targetCorrectionOffsetTicks;
|
||||
|
||||
double fullWrapTicks = Constants.TurretConstants.TURRET_FULL_WRAP_TICKS;
|
||||
double halfWrapTicks = fullWrapTicks / 2.0;
|
||||
|
||||
if (rawTarget > halfWrapTicks) {
|
||||
rawTarget -= fullWrapTicks;
|
||||
} else if (rawTarget < -halfWrapTicks) {
|
||||
rawTarget += fullWrapTicks;
|
||||
}
|
||||
|
||||
fusedTargetTicks = Range.clip(rawTarget, Constants.TurretConstants.SOFT_LIMIT_NEG, Constants.TurretConstants.SOFT_LIMIT_POS);
|
||||
targetTick = fusedTargetTicks;
|
||||
}*/ // <-- Old Logic (relies on both LL and ODO [Even while shooting]
|
||||
private void calculateHybridTarget(Pose robotPose, double currentDegrees, double currentTicks) {
|
||||
double odoTargetTicks = calculateOdometryTargetTicks(robotPose);
|
||||
|
||||
boolean isActivelyShooting = isLaunching();
|
||||
|
||||
if (!isActivelyShooting) {
|
||||
LLResult result = hardware.getLimelightResult();
|
||||
|
||||
if (result != null && result.isValid()) {
|
||||
double tx = result.getTx();
|
||||
double visionTargetDegrees = currentDegrees + (tx * Constants.TurretConstants.LL_LOGIC_MULTIPLIER);
|
||||
double finalVisionDegrees = visionTargetDegrees + Constants.TurretConstants.LL_TARGET_OFFSET_DEGREES;
|
||||
double visionTargetTicks = finalVisionDegrees * Constants.TurretConstants.TICKS_PER_DEGREE;
|
||||
|
||||
visionTargetTicks += kinematicAngularOffsetTicks;
|
||||
|
||||
double visionTargetWithManualOffset = visionTargetTicks + offsetTicks;
|
||||
double currentFusedTarget = odoTargetTicks + targetCorrectionOffsetTicks;
|
||||
double correctionError = visionTargetWithManualOffset - currentFusedTarget;
|
||||
|
||||
double ticksPerRev = 360.0 * Constants.TurretConstants.TICKS_PER_DEGREE;
|
||||
while (correctionError > (ticksPerRev / 2)) correctionError -= ticksPerRev;
|
||||
while (correctionError < -(ticksPerRev / 2)) correctionError += ticksPerRev;
|
||||
|
||||
targetCorrectionOffsetTicks += (correctionError * Constants.TurretConstants.OFFSET_SMOOTHING);
|
||||
}
|
||||
}
|
||||
|
||||
double rawTarget = odoTargetTicks + targetCorrectionOffsetTicks;
|
||||
|
||||
double fullWrapTicks = Constants.TurretConstants.TURRET_FULL_WRAP_TICKS;
|
||||
double halfWrapTicks = fullWrapTicks / 2.0;
|
||||
|
||||
if (rawTarget > halfWrapTicks) {
|
||||
rawTarget -= fullWrapTicks;
|
||||
} else if (rawTarget < -halfWrapTicks) {
|
||||
rawTarget += fullWrapTicks;
|
||||
}
|
||||
|
||||
fusedTargetTicks = Range.clip(rawTarget, Constants.TurretConstants.SOFT_LIMIT_NEG, Constants.TurretConstants.SOFT_LIMIT_POS);
|
||||
targetTick = fusedTargetTicks;
|
||||
}
|
||||
|
||||
private double calculateOdometryTargetTicks(Pose robotPose) {
|
||||
@@ -201,86 +335,138 @@ public class Turret {
|
||||
|
||||
while (relativeRad > Math.PI) relativeRad -= (2 * Math.PI);
|
||||
while (relativeRad < -Math.PI) relativeRad += (2 * Math.PI);
|
||||
|
||||
double relativeDegrees = Math.toDegrees(relativeRad);
|
||||
double staticOffset = (alliance == 2) ? Constants.TurretConstants.RED_TARGET_OFFSET_DEGREES : Constants.TurretConstants.BLUE_TARGET_OFFSET_DEGREES;
|
||||
|
||||
return (relativeDegrees + staticOffset) * Constants.TurretConstants.TICKS_PER_DEGREE;
|
||||
}
|
||||
|
||||
private double getErrorTicks(double currentDegrees, LLResult result, double odoTargetTicks) {
|
||||
double tx = result.getTx();
|
||||
double visionTargetDegrees = currentDegrees + (tx * Constants.TurretConstants.LL_LOGIC_MULTIPLIER);
|
||||
double finalVisionDegrees = visionTargetDegrees + Constants.TurretConstants.LL_TARGET_OFFSET_DEGREES;
|
||||
double visionTargetTicks = finalVisionDegrees * Constants.TurretConstants.TICKS_PER_DEGREE;
|
||||
|
||||
double rawErrorTicks = visionTargetTicks - odoTargetTicks;
|
||||
double ticksPerRev = 360.0 * Constants.TurretConstants.TICKS_PER_DEGREE;
|
||||
|
||||
while (rawErrorTicks > (ticksPerRev / 2)) rawErrorTicks -= ticksPerRev;
|
||||
while (rawErrorTicks < -(ticksPerRev / 2)) rawErrorTicks += ticksPerRev;
|
||||
return rawErrorTicks;
|
||||
// APPLY THE KINEMATIC SHIFT
|
||||
return ((relativeDegrees + staticOffset) * Constants.TurretConstants.TICKS_PER_DEGREE) + kinematicAngularOffsetTicks;
|
||||
}
|
||||
|
||||
private void runPIDControl(double currentTicks, double dt) {
|
||||
fusedTargetTicks = fusedTargetTicks + offsetTicks;
|
||||
double error = fusedTargetTicks - currentTicks;
|
||||
double derivative = (error - lastError) / dt;
|
||||
|
||||
if (Math.abs(error) < (15 * Constants.TurretConstants.TICKS_PER_DEGREE)) {
|
||||
integralSum += (error * dt);
|
||||
} else {
|
||||
integralSum = 0;
|
||||
double entryThreshold = 10;
|
||||
double exitThreshold = 30;
|
||||
|
||||
if (!turretModeHold && Math.abs(error) <= entryThreshold) {
|
||||
turretModeHold = true;
|
||||
} else if (turretModeHold && Math.abs(error) > exitThreshold) {
|
||||
turretModeHold = false;
|
||||
}
|
||||
|
||||
double integralTerm = Range.clip(Constants.TurretConstants.KI * integralSum, -Constants.TurretConstants.MAX_INTEGRAL, Constants.TurretConstants.MAX_INTEGRAL);
|
||||
double output = (Constants.TurretConstants.KP * error) + integralTerm + (Constants.TurretConstants.KD * derivative);
|
||||
output = Range.clip(output, -Constants.TurretConstants.MAX_POWER, Constants.TurretConstants.MAX_POWER);
|
||||
if (turretModeHold) {
|
||||
if (lastTurretModeHold != turretModeHold) {
|
||||
hardware.runToPos((int) fusedTargetTicks); // Set target first
|
||||
hardware.enableTurretHold();
|
||||
hardware.setTurretRotationPower(Constants.TurretConstants.TURRET_HOLD_POWER); // Set a holding power
|
||||
}
|
||||
hardware.runToPos((int) fusedTargetTicks); // Keep target updated even in hold mode
|
||||
} else {
|
||||
if (lastTurretModeHold != turretModeHold) {
|
||||
hardware.disableTurretHold();
|
||||
}
|
||||
|
||||
hardware.setTurretRotationPower(output);
|
||||
turretPowerRotation = output;
|
||||
if (Math.abs(error) < (15 * Constants.TurretConstants.TICKS_PER_DEGREE)) {
|
||||
integralSum += (error * dt);
|
||||
} else {
|
||||
integralSum = 0;
|
||||
}
|
||||
|
||||
double integralTerm = Range.clip(Constants.TurretConstants.KI * integralSum, -Constants.TurretConstants.MAX_INTEGRAL, Constants.TurretConstants.MAX_INTEGRAL);
|
||||
double output = (Constants.TurretConstants.KP * error) + integralTerm + (Constants.TurretConstants.KD * derivative);
|
||||
output = Range.clip(output, -Constants.TurretConstants.MAX_POWER, Constants.TurretConstants.MAX_POWER);
|
||||
|
||||
hardware.setTurretRotationPower(output);
|
||||
turretPowerRotation = output;
|
||||
}
|
||||
lastTurretModeHold = turretModeHold;
|
||||
lastError = error;
|
||||
}
|
||||
|
||||
public boolean hasReachedVelocity() {
|
||||
double currentVel = hardware.getFlywheelVelocities()[0];
|
||||
double currentVel = hardware.getFlywheelVelocities()[1];
|
||||
|
||||
if (Math.abs(targetVelocity) > 1000) {
|
||||
double absCurrent = Math.abs(currentVel);
|
||||
double absTarget = Math.abs(targetVelocity);
|
||||
|
||||
double error = Math.abs(absCurrent - absTarget);
|
||||
double tolerance = absTarget * 0.03;
|
||||
double tolerance = absTarget * 0.05;
|
||||
|
||||
return error <= tolerance;
|
||||
return error <= tolerance || absCurrent > absTarget;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isTurretReady() {
|
||||
return hasReachedVelocity();
|
||||
public boolean isTurretReady(boolean isAuton) {
|
||||
|
||||
if (!isAuton) return hasReachedVelocity() && isTurretRotationLocked();
|
||||
else return hasReachedVelocity();
|
||||
}
|
||||
|
||||
|
||||
public void updatePose(Pose robotPose) {
|
||||
public void updatePose(Pose robotPose, Vector robotVelocity) {
|
||||
this.robotPose = robotPose;
|
||||
this.robotVelocity = robotVelocity != null ? robotVelocity : new Vector(0, 0);
|
||||
calculateKinematicOffsets();
|
||||
}
|
||||
|
||||
private void calculateKinematicOffsets() {
|
||||
if (robotPose == null || robotVelocity == null) {
|
||||
kinematicDistanceOffset = 0;
|
||||
kinematicAngularOffsetTicks = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
double targetX = (alliance == 2) ? Constants.TurretConstants.GOAL_RED_X : Constants.TurretConstants.GOAL_BLUE_X;
|
||||
double targetY = (alliance == 2) ? Constants.TurretConstants.GOAL_RED_Y : Constants.TurretConstants.GOAL_BLUE_Y;
|
||||
|
||||
double virtualX = targetX - (robotVelocity.getXComponent() * Constants.TurretConstants.SHOT_TIME_OF_FLIGHT);
|
||||
double virtualY = targetY - (robotVelocity.getYComponent() * Constants.TurretConstants.SHOT_TIME_OF_FLIGHT);
|
||||
|
||||
double realDx = targetX - robotPose.getX();
|
||||
double realDy = targetY - robotPose.getY();
|
||||
double virtualDx = virtualX - robotPose.getX();
|
||||
double virtualDy = virtualY - robotPose.getY();
|
||||
|
||||
double realDistance = Math.hypot(realDx, realDy);
|
||||
double virtualDistance = Math.hypot(virtualDx, virtualDy);
|
||||
kinematicDistanceOffset = virtualDistance - realDistance;
|
||||
|
||||
double realAngle = Math.atan2(realDy, realDx);
|
||||
double virtualAngle = Math.atan2(virtualDy, virtualDx);
|
||||
|
||||
double angleDiff = virtualAngle - realAngle;
|
||||
while (angleDiff > Math.PI) angleDiff -= (2 * Math.PI);
|
||||
while (angleDiff < -Math.PI) angleDiff += (2 * Math.PI);
|
||||
|
||||
kinematicAngularOffsetTicks = Math.toDegrees(angleDiff) * Constants.TurretConstants.TICKS_PER_DEGREE;
|
||||
}
|
||||
|
||||
public double getDistance() {
|
||||
if (hardware.hasTarget()) {
|
||||
double targetX = (alliance == 2) ? Constants.TurretConstants.GOAL_RED_X : Constants.TurretConstants.GOAL_BLUE_X;
|
||||
double targetY = (alliance == 2) ? Constants.TurretConstants.GOAL_RED_Y : Constants.TurretConstants.GOAL_BLUE_Y;
|
||||
|
||||
double odoDistance = 0.0;
|
||||
if (robotPose != null) {
|
||||
odoDistance = Math.hypot(targetX - robotPose.getX(), targetY - robotPose.getY());
|
||||
}
|
||||
|
||||
boolean isActivelyShooting = isLaunching();
|
||||
|
||||
if (!isActivelyShooting && hardware.hasTarget()) {
|
||||
double ty = hardware.getTargetTY();
|
||||
double angleToGoalDegrees = Constants.TurretConstants.CAMERA_MOUNT_ANGLE_DEGREES + ty;
|
||||
double angleToGoalRadians = Math.toRadians(angleToGoalDegrees);
|
||||
|
||||
return (Constants.TurretConstants.GOAL_HEIGHT_INCHES - Constants.TurretConstants.CAMERA_HEIGHT_INCHES) / Math.tan(angleToGoalRadians);
|
||||
}
|
||||
else if (robotPose != null) {
|
||||
double targetX = (alliance == 2) ? Constants.TurretConstants.GOAL_RED_X : Constants.TurretConstants.GOAL_BLUE_X;
|
||||
double targetY = (alliance == 2) ? Constants.TurretConstants.GOAL_RED_Y : Constants.TurretConstants.GOAL_BLUE_Y;
|
||||
double rawVisionDistance = (Constants.TurretConstants.GOAL_HEIGHT_INCHES - Constants.TurretConstants.CAMERA_HEIGHT_INCHES) / Math.tan(angleToGoalRadians);
|
||||
|
||||
return Math.hypot(targetX - robotPose.getX(), targetY - robotPose.getY());
|
||||
double distanceError = rawVisionDistance - odoDistance;
|
||||
|
||||
visionDistanceOffset += (distanceError - visionDistanceOffset) * 0.1;
|
||||
}
|
||||
return 0.0;
|
||||
return odoDistance + visionDistanceOffset;
|
||||
}
|
||||
|
||||
private double calculateHoodOffset(double target, double current) {
|
||||
@@ -288,11 +474,49 @@ public class Turret {
|
||||
}
|
||||
|
||||
private double getFlywheelVelocity(double dist) {
|
||||
return (0.0000119972 * Math.pow((dist), 4) - 0.00249603 * Math.pow(dist, 3) + 0.179513 * Math.pow(dist, 2) + (0.0519688 * dist) + 1489.8908);
|
||||
}
|
||||
if (dist <= 0) return 0;
|
||||
|
||||
if (dist < 19.0) {
|
||||
return 1300.0;
|
||||
}
|
||||
|
||||
if (dist > 145.0) {
|
||||
return 2300.0;
|
||||
}
|
||||
|
||||
double x = dist;
|
||||
double x2 = x * x;
|
||||
double x3 = x2 * x;
|
||||
double x4 = x3 * x;
|
||||
|
||||
double velocity = (-0.0000218345 * x4)
|
||||
+ (0.00636447 * x3)
|
||||
+ (-0.593959 * x2)
|
||||
+ (26.08276 * x)
|
||||
+ 1340.12895;
|
||||
|
||||
return Range.clip(velocity, 1300.0, 2450.0);
|
||||
}
|
||||
private double getHoodPOS(double dist) {
|
||||
return (((1.2113 * Math.pow(10, -8)) * Math.pow(dist, 4)) - (0.00000498646 * Math.pow(dist, 3)) + (0.00068726 * Math.pow(dist, 2)) + (-0.0405783 * dist) + 1.07118);
|
||||
if (dist < 20.0) {
|
||||
return 0.36;
|
||||
}
|
||||
|
||||
if (dist > 125.0) {
|
||||
return 0.09;
|
||||
}
|
||||
double x = dist;
|
||||
double x2 = x * x;
|
||||
double x3 = x2 * x;
|
||||
double x4 = x3 * x;
|
||||
|
||||
double hoodPos = (5.34037e-9 * x4)
|
||||
+ (-1.70158e-6 * x3)
|
||||
+ (2.04794e-4 * x2)
|
||||
+ (-0.013153 * x)
|
||||
+ 0.55256;
|
||||
|
||||
return Range.clip(hoodPos, Constants.TurretConstants.SERVO_MIN, Constants.TurretConstants.SERVO_MAX);
|
||||
}
|
||||
|
||||
public void setHoodPos(double pos) {
|
||||
@@ -305,13 +529,49 @@ public class Turret {
|
||||
|
||||
public void updateOffsetTicks(double change) {
|
||||
offsetTicks += change;
|
||||
targetCorrectionOffsetTicks += change;
|
||||
}
|
||||
|
||||
public double getTurretPower() {
|
||||
return turretPower;
|
||||
}
|
||||
|
||||
public double returnFlywheelSpeed() {
|
||||
return hardware.getFlywheelVelocities()[1];
|
||||
}
|
||||
|
||||
public void setPIDF(double[] PIDF) {
|
||||
hardware.setPIDF(PIDF[0], PIDF[1], PIDF[2], PIDF[3]);
|
||||
}
|
||||
|
||||
|
||||
public double getTargetVelocity() {
|
||||
return targetVelocity;
|
||||
}
|
||||
|
||||
|
||||
public void resetTurret() {
|
||||
hardware.resetTurret();
|
||||
}
|
||||
|
||||
public boolean isTurretRotationLocked() {
|
||||
return turretModeHold && Math.abs(lastError) <= 10;
|
||||
}
|
||||
|
||||
public void updateDistanceOffset(double offset) {
|
||||
distanceOffset += offset;
|
||||
}
|
||||
public void setDistanceOffset(double offset) {
|
||||
distanceOffset = offset;
|
||||
}
|
||||
|
||||
|
||||
public void setLaunching(boolean state) {
|
||||
isLaunching = state;
|
||||
}
|
||||
|
||||
public boolean isLaunching() {
|
||||
return isLaunching;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -5,7 +5,8 @@ import com.pedropathing.geometry.Pose;
|
||||
import com.qualcomm.robotcore.hardware.DcMotor;
|
||||
import com.qualcomm.robotcore.hardware.DcMotorSimple;
|
||||
import com.qualcomm.robotcore.hardware.Servo;
|
||||
@Configurable
|
||||
|
||||
|
||||
public class Constants {
|
||||
|
||||
public static class FieldConstants {
|
||||
@@ -37,6 +38,17 @@ public class Constants {
|
||||
public static final double TURBO_SPEED_MULTIPLIER = 1.0;
|
||||
}
|
||||
|
||||
public static class LEDConstants {
|
||||
public static final String LED = "prism";
|
||||
|
||||
// TODO: Tune these!
|
||||
public static final double COLOR_RED = 0.301;
|
||||
public static final double COLOR_GREEN = 0.5;
|
||||
public static final double COLOR_ORANGE = 0.32;
|
||||
public static final double COLOR_YELLOW = 0.38;
|
||||
}
|
||||
|
||||
|
||||
public static class IntakeConstants {
|
||||
public static final String FRONT_INTAKE_MOTOR = "intake";
|
||||
|
||||
@@ -68,6 +80,9 @@ public class Constants {
|
||||
public static final double POWER_HOLDING = 0.1;
|
||||
}
|
||||
|
||||
|
||||
@Configurable
|
||||
|
||||
public static class TransferConstants {
|
||||
public static final String LIMITER_SERVO = "limiter";
|
||||
|
||||
@@ -82,38 +97,45 @@ public class Constants {
|
||||
|
||||
public static final double UNLOCK_POS = 0.82;
|
||||
|
||||
public static double launch_duration = 0.9;
|
||||
|
||||
}
|
||||
|
||||
@Configurable
|
||||
public static class TurretConstants {
|
||||
public static final double TICKS_PER_REV_MOTOR = 384.5;
|
||||
public static final double EXTERNAL_GEAR_RATIO = 2.68888889;
|
||||
public static double TICKS_PER_REV_MOTOR = 145.1;
|
||||
public static double EXTERNAL_GEAR_RATIO = 9.179875;
|
||||
public static final double TICKS_PER_DEGREE = (TICKS_PER_REV_MOTOR * EXTERNAL_GEAR_RATIO) / 360.0;
|
||||
|
||||
public static final double KP = 0.02;
|
||||
public static final double KI = 0.0;
|
||||
public static final double KD = 0.001;
|
||||
public static final double MAX_POWER = 0.6;
|
||||
public static double KP = 0.0043;
|
||||
public static double KI = 0.00801;
|
||||
public static double KD = 0.00076;
|
||||
public static final double MAX_POWER = 0.8;
|
||||
public static final double MAX_INTEGRAL = 0.5;
|
||||
// PIDF Values P I D F
|
||||
public static double[] PIDF_NORMAL = {1.3, 0, 2, 13.5};
|
||||
|
||||
public static final double GOAL_RED_X = 138;
|
||||
public static final double GOAL_RED_Y = 138;
|
||||
public static final double GOAL_BLUE_X = 6;
|
||||
public static final double GOAL_BLUE_Y = 138;
|
||||
public static double[] PIDF_Shooting = {27, 0, 2, 2.4};
|
||||
|
||||
public static final double RED_TARGET_OFFSET_DEGREES = 14;
|
||||
public static final double BLUE_TARGET_OFFSET_DEGREES = 17;
|
||||
public static final double LL_TARGET_OFFSET_DEGREES = -2;
|
||||
public static final double LL_LOGIC_MULTIPLIER = 1.0;
|
||||
public static final double OFFSET_SMOOTHING = 0.2;
|
||||
public static double GOAL_RED_X = 140;
|
||||
public static double GOAL_RED_Y = 140;
|
||||
public static double GOAL_BLUE_X = 4;
|
||||
public static double GOAL_BLUE_Y = 140;
|
||||
|
||||
public static double RED_TARGET_OFFSET_DEGREES = 0;
|
||||
public static double BLUE_TARGET_OFFSET_DEGREES = 0;
|
||||
public static double LL_TARGET_OFFSET_DEGREES = 0;
|
||||
public static double LL_LOGIC_MULTIPLIER = -1.0;
|
||||
public static double OFFSET_SMOOTHING = 0.2;
|
||||
|
||||
public static final DcMotorSimple.Direction TURRET_ROTATION_DIR = DcMotorSimple.Direction.FORWARD;
|
||||
|
||||
public static final double SOFT_LIMIT_NEG = -230;
|
||||
public static final double SOFT_LIMIT_POS = 230;
|
||||
public static double SOFT_LIMIT_NEG = -370;
|
||||
public static double SOFT_LIMIT_POS = 370;
|
||||
|
||||
public static final double HOOD_POS_CLOSE = 0.3;
|
||||
public static final double HOOD_POS_FAR = 0.7;
|
||||
public static final double HOOD_POS_MID = 0.5;
|
||||
public static final double HOOD_POS_CLOSE = 0.1;
|
||||
public static final double HOOD_POS_FAR = 0.5;
|
||||
public static final double HOOD_POS_MID = 0.3;
|
||||
|
||||
public static double HOOD_OFFSET = 0.3;
|
||||
|
||||
@@ -122,6 +144,7 @@ public class Constants {
|
||||
public static final double TURRET_POWER_MID = -0.84;
|
||||
public static final double TURRET_POWER_MAX = -1;
|
||||
public static final double TURRET_POWER_LOW = -0.7;
|
||||
public static final double TURRET_HOLD_POWER = 1.0;
|
||||
|
||||
public static final double EXTAKE_POWER = 0.3;
|
||||
public static final double INTAKE_POWER = -0.04;
|
||||
@@ -140,12 +163,27 @@ public class Constants {
|
||||
public static final int LIMELIGHT_PIPELINE_BLUE_TARGET = 1;
|
||||
public static final int LIMELIGHT_PIPELINE_RED_TARGET = 2;
|
||||
|
||||
public static final double CAMERA_HEIGHT_INCHES = 12.4;
|
||||
public static final double GOAL_HEIGHT_INCHES = 29.5;
|
||||
public static final double CAMERA_MOUNT_ANGLE_DEGREES = 7.9;
|
||||
public static double CAMERA_HEIGHT_INCHES = 12.75;
|
||||
public static double GOAL_HEIGHT_INCHES = 29.5;
|
||||
public static double CAMERA_MOUNT_ANGLE_DEGREES = 19.8;
|
||||
|
||||
public static final double SERVO_MAX = 0.5;
|
||||
public static final double SERVO_MIN = 0;
|
||||
public static double LL_POSE_HEALING_SMOOTHING = 0.05;
|
||||
public static double TURRET_FULL_WRAP_TICKS = 1340.0;
|
||||
|
||||
// Artifact Compensation Tuning
|
||||
// Lower (negative offset) for 1st and 3rd, Normal (0 offset) for 2
|
||||
public static double ARTIFACT_1 = -95.0;
|
||||
public static double ARTIFACT_2 = 45.0;
|
||||
|
||||
public static double ARTIFACT_3 = 20.0;
|
||||
|
||||
// Timing Windows (seconds)
|
||||
public static double ARTIFACT_1_WINDOW = 0.35;
|
||||
public static double ARTIFACT_2_WINDOW = 0.55;
|
||||
|
||||
public static double SHOT_TIME_OF_FLIGHT = 0.83;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -12,8 +12,15 @@ import org.firstinspires.ftc.teamcode.subsystems.Intake;
|
||||
import org.firstinspires.ftc.teamcode.subsystems.TransferSys;
|
||||
import org.firstinspires.ftc.teamcode.util.AutoTransfer;
|
||||
import org.firstinspires.ftc.teamcode.util.FPSCounter;
|
||||
|
||||
import com.qualcomm.hardware.lynx.LynxModule;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.pedropathing.math.Vector;
|
||||
|
||||
import com.qualcomm.robotcore.hardware.VoltageSensor;
|
||||
|
||||
public class SOLOTeleOP {
|
||||
|
||||
@TeleOp(name = "Red SOLO", group = "FINAL")
|
||||
@@ -22,6 +29,7 @@ public class SOLOTeleOP {
|
||||
super(2);
|
||||
}
|
||||
}
|
||||
|
||||
@TeleOp(name = "Blue SOLO", group = "FINAL")
|
||||
public static class BlueSOLO extends BaseSoloTeleOp {
|
||||
public BlueSOLO() {
|
||||
@@ -35,14 +43,17 @@ public class SOLOTeleOP {
|
||||
private Follower follower;
|
||||
private int currentAlliance;
|
||||
private final int initialAlliance;
|
||||
private boolean isScoringActive = false;
|
||||
protected List<LynxModule> allHubs;
|
||||
|
||||
|
||||
private final Pose DEFAULT_RED_START = new Pose(129.25, 112, Math.toRadians(90));
|
||||
private final Pose DEFAULT_BLUE_START = new Pose(14.75, 112, Math.toRadians(90));
|
||||
|
||||
protected FPSCounter fpsCounter = new FPSCounter();
|
||||
|
||||
private boolean isScoringActive = false;
|
||||
|
||||
|
||||
public BaseSoloTeleOp(int alliance) {
|
||||
this.initialAlliance = alliance;
|
||||
this.currentAlliance = 0;
|
||||
@@ -63,6 +74,7 @@ public class SOLOTeleOP {
|
||||
currentAlliance = initialAlliance;
|
||||
if (currentAlliance == 2) follower.setStartingPose(DEFAULT_RED_START);
|
||||
else follower.setStartingPose(DEFAULT_BLUE_START);
|
||||
stateMachine.getTurret().resetTurret();
|
||||
telemetry.addLine("MANUAL START - NO AUTON DATA");
|
||||
}
|
||||
|
||||
@@ -90,17 +102,14 @@ public class SOLOTeleOP {
|
||||
|
||||
follower.update();
|
||||
Pose currentPose = follower.getPose();
|
||||
Vector currentVelocity = follower.getVelocity();
|
||||
|
||||
stateMachine.update(false, false, currentPose, currentVelocity);
|
||||
|
||||
//Pose healingPose = stateMachine.getTurret().getSelfHealingPose();
|
||||
//if (healingPose != null) {
|
||||
// follower.setPose(healingPose);
|
||||
//}
|
||||
|
||||
handleGlobalLogic();
|
||||
handleDriverControls();
|
||||
|
||||
stateMachine.update(false, false, currentPose);
|
||||
|
||||
|
||||
updateTelemetry(currentPose);
|
||||
}
|
||||
@@ -137,7 +146,7 @@ public class SOLOTeleOP {
|
||||
|
||||
private void configureStartSettings() {
|
||||
stateMachine.setRobotState(RobotState.TELEOP);
|
||||
stateMachine.getDriveTrain().setDriveState(DriveTrain.DriveState.NORMAL);
|
||||
stateMachine.getDriveTrain().setDriveState(DriveTrain.DriveState.TURBO);
|
||||
stateMachine.getTurret().setLaunchPower(org.firstinspires.ftc.teamcode.teleOp.Constants.TurretConstants.TURRET_POWER_MID);
|
||||
stateMachine.getTransfer().closeLimiter();
|
||||
stateMachine.initUpdate();
|
||||
@@ -159,9 +168,8 @@ public class SOLOTeleOP {
|
||||
}
|
||||
|
||||
if (stateMachine.getCurrentGameState() != GameState.SCORING) {
|
||||
if (!stateMachine.getTurret().hasReachedVelocity()) {
|
||||
int rumbleDuration = (int) fpsCounter.getCurrentLoopTime() + 2;
|
||||
gamepad1.rumble(rumbleDuration);
|
||||
if (!stateMachine.getTurret().hasReachedVelocity() && (System.currentTimeMillis() % 100 < 10)) {
|
||||
gamepad1.rumble(50);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -172,9 +180,12 @@ public class SOLOTeleOP {
|
||||
|
||||
private void handleDriverControls() {
|
||||
|
||||
if (gamepad1.dpad_up) stateMachine.getDriveTrain().setDriveState(DriveTrain.DriveState.TURBO);
|
||||
else if (gamepad1.dpad_left) stateMachine.getDriveTrain().setDriveState(DriveTrain.DriveState.NORMAL);
|
||||
else if (gamepad1.dpad_down) stateMachine.getDriveTrain().setDriveState(DriveTrain.DriveState.PRECISION);
|
||||
if (gamepad1.dpad_up)
|
||||
stateMachine.getDriveTrain().setDriveState(DriveTrain.DriveState.TURBO);
|
||||
else if (gamepad1.dpad_left)
|
||||
stateMachine.getDriveTrain().setDriveState(DriveTrain.DriveState.NORMAL);
|
||||
else if (gamepad1.dpad_down)
|
||||
stateMachine.getDriveTrain().setDriveState(DriveTrain.DriveState.PRECISION);
|
||||
|
||||
if (stateMachine.getCurrentGameState() != GameState.SCORING) {
|
||||
if (gamepad1.right_trigger > 0.1) {
|
||||
@@ -192,17 +203,20 @@ public class SOLOTeleOP {
|
||||
if (gamepad1.yWasPressed()) {
|
||||
isScoringActive = !isScoringActive;
|
||||
if (isScoringActive) stateMachine.setGameState(GameState.SCORING);
|
||||
else if (stateMachine.getCurrentGameState() == GameState.SCORING) stateMachine.setGameState(GameState.IDLE);
|
||||
else if (stateMachine.getCurrentGameState() == GameState.SCORING)
|
||||
stateMachine.setGameState(GameState.IDLE);
|
||||
}
|
||||
|
||||
if (gamepad1.right_bumper) stateMachine.getTurret().updateOffsetTicks(0.06);
|
||||
if (gamepad1.left_bumper) stateMachine.getTurret().updateOffsetTicks(-0.06);
|
||||
|
||||
if (gamepad1.right_bumper) stateMachine.getTurret().updateOffsetTicks(3);
|
||||
if (gamepad1.left_bumper) stateMachine.getTurret().updateOffsetTicks(-3);
|
||||
|
||||
if (gamepad1.aWasPressed()) {
|
||||
stateMachine.forceLaunchSequence();
|
||||
}
|
||||
}
|
||||
|
||||
private void updateTelemetry(Pose p) {
|
||||
telemetry.addData("OpMod ev", "SOLO TeleOp");
|
||||
telemetry.addData("OpMode", "SOLO TeleOp");
|
||||
telemetry.addData("Avg FPS", "%.2f", fpsCounter.getAverageFps());
|
||||
|
||||
telemetry.addLine("▰▰▰▰▰▰▰ SYSTEMS ▰▰▰▰▰▰▰");
|
||||
@@ -212,11 +226,13 @@ public class SOLOTeleOP {
|
||||
telemetry.addData("Anchor", stateMachine.getDriveTrain().isAnchorActive() ? "LOCKED" : "FREE");
|
||||
telemetry.addData("Alliance", currentAlliance == 2 ? "RED" : "BLUE");
|
||||
telemetry.addData("Drive Speed", stateMachine.getDriveTrain().getDriveState());
|
||||
telemetry.addData("Flywheel RPM", stateMachine.getTurret().returnFlywheelSpeed());
|
||||
|
||||
telemetry.addLine("▰▰▰▰▰▰▰ TRACKING ▰▰▰▰▰▰▰");
|
||||
telemetry.addData("Pose", "X:%.1f Y:%.1f H:%.1f°", p.getX(), p.getY(), Math.toDegrees(p.getHeading()));
|
||||
telemetry.addData("Distance", "%.1f in", stateMachine.getTurret().getDistance());
|
||||
telemetry.addData("Turret Ready", stateMachine.getTurret().isTurretReady());
|
||||
telemetry.addData("Turret Ready", stateMachine.getTurret().isTurretReady(false));
|
||||
telemetry.addData("Target Tick", stateMachine.getTurret().targetTick);
|
||||
|
||||
telemetry.update();
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package org.firstinspires.ftc.teamcode.teleOp;
|
||||
|
||||
import com.pedropathing.geometry.Pose; // ADDED
|
||||
import com.pedropathing.math.Vector;
|
||||
import com.qualcomm.robotcore.hardware.HardwareMap;
|
||||
import com.qualcomm.robotcore.util.ElapsedTime;
|
||||
|
||||
import org.firstinspires.ftc.teamcode.Hware.hwMap;
|
||||
import org.firstinspires.ftc.teamcode.subsystems.DriveTrain;
|
||||
@@ -29,11 +31,17 @@ public class StateMachine {
|
||||
private final Lift m_lift;
|
||||
|
||||
private final LED m_led;
|
||||
private final ElapsedTime ledTimer = new ElapsedTime();
|
||||
|
||||
boolean isMotifEdited = false;
|
||||
private long lastIndexAllArtifactsTime = 0;
|
||||
|
||||
public boolean isIntakeLaunching = false;
|
||||
private boolean isForceLaunch = false;
|
||||
|
||||
private boolean PIDFShooting = false;
|
||||
|
||||
private boolean lastPIDFShooting = PIDFShooting;
|
||||
|
||||
public StateMachine(hwMap.DriveHwMap h_driveTrain, hwMap.IntakeHwMap h_intake, hwMap.LiftHwMap h_lift, hwMap.TransferHwMap h_transfer, hwMap.TurretHwMap h_turret, hwMap.LedHwMap h_led, int initialMotif, int alliance) {
|
||||
this.m_driveTrain = new DriveTrain(h_driveTrain);
|
||||
@@ -44,6 +52,10 @@ public class StateMachine {
|
||||
this.m_led = new LED(h_led);
|
||||
|
||||
|
||||
m_turret.setPIDF(Constants.TurretConstants.PIDF_NORMAL);
|
||||
m_turret.setLaunching(false);
|
||||
|
||||
|
||||
setRobotState(RobotState.INIT);
|
||||
setGameState(GameState.IDLE);
|
||||
}
|
||||
@@ -69,6 +81,7 @@ public class StateMachine {
|
||||
m_turret.setTurretState(Turret.TurretState.IDLE);
|
||||
m_intake.setIntakeState(Intake.IntakeState.IDLE);
|
||||
isIntakeLaunching = false;
|
||||
isForceLaunch = false;
|
||||
//m_driveTrain.setDriveState(DriveTrain.DriveState.NORMAL);
|
||||
m_driveTrain.stopAnchor();
|
||||
break;
|
||||
@@ -78,26 +91,45 @@ public class StateMachine {
|
||||
}
|
||||
}
|
||||
|
||||
public void update(boolean manualSAM, boolean manualTracking, Pose currentPose) {
|
||||
public void update(boolean manualSAM, boolean manualTracking, Pose currentPose, Vector currentVelocity) {
|
||||
m_driveTrain.update();
|
||||
|
||||
m_turret.update(manualTracking, manualSAM, currentPose);
|
||||
m_turret.update(manualTracking, manualSAM, currentPose, currentVelocity, m_transfer.getLaunchElapsedTime());
|
||||
|
||||
if (currentGameState == GameState.SCORING) {
|
||||
m_transfer.updateTurretReady(m_turret.hasReachedVelocity());
|
||||
if (m_turret.hasReachedVelocity()) {
|
||||
if (!isForceLaunch) {
|
||||
m_transfer.updateTurretReady(m_turret.hasReachedVelocity());
|
||||
}
|
||||
|
||||
if (m_turret.hasReachedVelocity() || isForceLaunch || PIDFShooting) {
|
||||
isIntakeLaunching = true;
|
||||
m_intake.setIntakeState(Intake.IntakeState.LAUNCH);
|
||||
PIDFShooting = true;
|
||||
}
|
||||
} else {
|
||||
PIDFShooting = false;
|
||||
}
|
||||
|
||||
if (PIDFShooting != lastPIDFShooting) {
|
||||
if (PIDFShooting) {
|
||||
|
||||
m_turret.setLaunching(true);
|
||||
m_turret.setPIDF(Constants.TurretConstants.PIDF_Shooting);
|
||||
} else {
|
||||
|
||||
m_turret.setLaunching(false);
|
||||
m_turret.setPIDF(Constants.TurretConstants.PIDF_NORMAL);
|
||||
}
|
||||
}
|
||||
lastPIDFShooting = PIDFShooting;
|
||||
|
||||
|
||||
|
||||
m_transfer.update();
|
||||
|
||||
m_led.update(
|
||||
currentGameState == GameState.SCORING,
|
||||
m_turret.hasReachedVelocity(),
|
||||
m_turret.hasTarget(),
|
||||
m_driveTrain.isAnchorActive()
|
||||
m_turret.isTurretRotationLocked(),
|
||||
m_turret.hasReachedVelocity()
|
||||
);
|
||||
|
||||
if (currentGameState == GameState.SCORING) {
|
||||
@@ -108,7 +140,7 @@ public class StateMachine {
|
||||
}
|
||||
|
||||
public void initUpdate() {
|
||||
m_led.update(false, false, false, false);
|
||||
m_led.update(false, false);
|
||||
}
|
||||
|
||||
private void handleGameStateEntry(GameState newState) {
|
||||
@@ -182,6 +214,14 @@ public class StateMachine {
|
||||
setGameState(GameState.IDLE);
|
||||
}
|
||||
|
||||
public void forceLaunchSequence() {
|
||||
setGameState(GameState.SCORING);
|
||||
isForceLaunch = true;
|
||||
m_transfer.updateTurretReady(true);
|
||||
m_intake.setIntakeState(Intake.IntakeState.LAUNCH);
|
||||
isIntakeLaunching = true;
|
||||
}
|
||||
|
||||
public DriveTrain getDriveTrain() { return m_driveTrain; }
|
||||
public Intake getIntake() { return m_intake; }
|
||||
public Turret getTurret() { return m_turret; }
|
||||
|
||||
@@ -10,11 +10,14 @@ import org.firstinspires.ftc.teamcode.Hware.hwMap;
|
||||
import org.firstinspires.ftc.teamcode.pedroPathing.Constants;
|
||||
import org.firstinspires.ftc.teamcode.subsystems.DriveTrain;
|
||||
import org.firstinspires.ftc.teamcode.subsystems.Intake;
|
||||
import org.firstinspires.ftc.teamcode.subsystems.TransferSys;
|
||||
import org.firstinspires.ftc.teamcode.util.AutoTransfer;
|
||||
import org.firstinspires.ftc.teamcode.util.FPSCounter;
|
||||
import com.qualcomm.hardware.lynx.LynxModule;
|
||||
import java.util.List;
|
||||
|
||||
import com.pedropathing.math.Vector;
|
||||
|
||||
public class finalTeleOp {
|
||||
|
||||
@TeleOp(name = "Red Final", group = "FINAL")
|
||||
@@ -65,7 +68,7 @@ public class finalTeleOp {
|
||||
if (AutoTransfer.isAutonRan) {
|
||||
currentAlliance = AutoTransfer.alliance;
|
||||
if (currentAlliance != initialAlliance) {
|
||||
telemetry.addLine("WARNING: AUTON ALLIANCE DOES NOT MATCH TELEOP ALLIANCE!");
|
||||
telemetry.addLine("!!! WARNING: AUTON ALLIANCE DOES NOT MATCH TELEOP ALLIANCE!");
|
||||
}
|
||||
follower.setStartingPose(AutoTransfer.transferPose);
|
||||
telemetry.addLine("AUTON DATA LOADED");
|
||||
@@ -73,6 +76,7 @@ public class finalTeleOp {
|
||||
currentAlliance = initialAlliance;
|
||||
if (currentAlliance == 2) follower.setStartingPose(DEFAULT_RED_START);
|
||||
else follower.setStartingPose(DEFAULT_BLUE_START);
|
||||
stateMachine.getTurret().resetTurret();
|
||||
telemetry.addLine("MANUAL START - NO AUTON DATA");
|
||||
}
|
||||
|
||||
@@ -91,7 +95,7 @@ public class finalTeleOp {
|
||||
|
||||
if (stateMachine.getCurrentGameState() != GameState.SCORING) {
|
||||
stateMachine.getTransfer().closeLimiter();
|
||||
} else if (stateMachine.getCurrentGameState() == GameState.SCORING && stateMachine.getTurret().isTurretReady()) {
|
||||
} else if (stateMachine.getCurrentGameState() == GameState.SCORING && stateMachine.getTurret().isTurretReady(false)) {
|
||||
stateMachine.getTransfer().openLimiter();
|
||||
}
|
||||
|
||||
@@ -101,26 +105,14 @@ public class finalTeleOp {
|
||||
|
||||
follower.update();
|
||||
Pose currentPose = follower.getPose();
|
||||
Vector currentVelocity = follower.getVelocity();
|
||||
|
||||
|
||||
handleGlobalLogic();
|
||||
handleDriverInput();
|
||||
handleOperatorInput();
|
||||
|
||||
stateMachine.update(manualSAM, manualTracking, currentPose);
|
||||
//Pose healingPose = stateMachine.getTurret().getSelfHealingPose();
|
||||
|
||||
// if (healingPose != null) {
|
||||
// follower.setPose(healingPose);
|
||||
// }
|
||||
|
||||
if (gamepad2.a) {
|
||||
stateMachine.getTransfer().openLimiter();
|
||||
}
|
||||
else {
|
||||
if (stateMachine.getCurrentGameState() != GameState.SCORING) {
|
||||
stateMachine.getTransfer().closeLimiter();
|
||||
}
|
||||
}
|
||||
stateMachine.update(manualSAM, manualTracking, currentPose, currentVelocity);
|
||||
|
||||
|
||||
updateTelemetry(currentPose);
|
||||
@@ -148,15 +140,14 @@ public class finalTeleOp {
|
||||
currentAlliance
|
||||
);
|
||||
|
||||
|
||||
stateMachine.getTransfer().closeLimiter();
|
||||
stateMachine.getTransfer().setTransferState(TransferSys.TransferState.STOP);
|
||||
|
||||
stateMachine.getTurret().setAlliance(currentAlliance);
|
||||
}
|
||||
|
||||
private void configureStartSettings() {
|
||||
stateMachine.setRobotState(RobotState.TELEOP);
|
||||
stateMachine.getDriveTrain().setDriveState(DriveTrain.DriveState.NORMAL);
|
||||
stateMachine.getDriveTrain().setDriveState(DriveTrain.DriveState.TURBO);
|
||||
stateMachine.getTurret().setLaunchPower(org.firstinspires.ftc.teamcode.teleOp.Constants.TurretConstants.TURRET_POWER_MID);
|
||||
stateMachine.getTransfer().closeLimiter();
|
||||
stateMachine.initUpdate();
|
||||
@@ -168,9 +159,10 @@ public class finalTeleOp {
|
||||
stateMachine.emergencyStop();
|
||||
}
|
||||
|
||||
if (stateMachine.getCurrentGameState() != GameState.SCORING && !stateMachine.getTurret().hasReachedVelocity()) {
|
||||
int rumbleDuration = (int) fpsCounter.getCurrentLoopTime() + 2;
|
||||
gamepad2.rumble(rumbleDuration);
|
||||
if (stateMachine.getCurrentGameState() != GameState.SCORING) {
|
||||
if (!stateMachine.getTurret().hasReachedVelocity() && (System.currentTimeMillis() % 100 < 10)) {
|
||||
gamepad1.rumble(50);
|
||||
}
|
||||
}
|
||||
|
||||
if (gamepad1.psWasPressed()) {
|
||||
@@ -218,8 +210,8 @@ public class finalTeleOp {
|
||||
|
||||
|
||||
|
||||
if (gamepad2.right_bumper) stateMachine.getTurret().updateOffsetTicks(-0.6);
|
||||
if (gamepad2.left_bumper) stateMachine.getTurret().updateOffsetTicks(0.6);
|
||||
if (gamepad2.right_bumper) stateMachine.getTurret().updateOffsetTicks(1);
|
||||
if (gamepad2.left_bumper) stateMachine.getTurret().updateOffsetTicks(-1);
|
||||
}
|
||||
|
||||
private void handleOperatorInput() {
|
||||
@@ -240,30 +232,22 @@ public class finalTeleOp {
|
||||
manualTracking = !manualTracking;
|
||||
}
|
||||
|
||||
if (manualSAM) {
|
||||
handleManualSAM();
|
||||
}
|
||||
}
|
||||
|
||||
private void handleManualSAM() {
|
||||
if (gamepad2.dpad_up) {
|
||||
stateMachine.getTurret().setLaunchPower(org.firstinspires.ftc.teamcode.teleOp.Constants.TurretConstants.TURRET_POWER_MAX);
|
||||
stateMachine.getTurret().setHoodPos(org.firstinspires.ftc.teamcode.teleOp.Constants.TurretConstants.HOOD_POS_FAR);
|
||||
} else if (gamepad2.dpad_left) {
|
||||
stateMachine.getTurret().setLaunchPower(org.firstinspires.ftc.teamcode.teleOp.Constants.TurretConstants.TURRET_POWER_MID);
|
||||
stateMachine.getTurret().setHoodPos(org.firstinspires.ftc.teamcode.teleOp.Constants.TurretConstants.HOOD_POS_MID);
|
||||
} else if (gamepad2.dpad_down) {
|
||||
stateMachine.getTurret().setLaunchPower(org.firstinspires.ftc.teamcode.teleOp.Constants.TurretConstants.TURRET_POWER_LOW);
|
||||
stateMachine.getTurret().setHoodPos(org.firstinspires.ftc.teamcode.teleOp.Constants.TurretConstants.HOOD_POS_CLOSE);
|
||||
if (gamepad2.aWasPressed()) {
|
||||
stateMachine.forceLaunchSequence();
|
||||
}
|
||||
|
||||
if (Math.abs(gamepad2.left_stick_y) > 0.13) {
|
||||
hoodPosition += -gamepad2.left_stick_y * 0.05;
|
||||
hoodPosition = Range.clip(hoodPosition, 0.0, 1.0);
|
||||
if (gamepad2.dpadUpWasPressed()) {
|
||||
stateMachine.getTurret().updateDistanceOffset(7);
|
||||
} else if (gamepad2.dpadDownWasPressed()) {
|
||||
stateMachine.getTurret().updateDistanceOffset(7);
|
||||
} else if (gamepad2.dpadLeftWasPressed()) {
|
||||
stateMachine.getTurret().setDistanceOffset(0);
|
||||
}
|
||||
stateMachine.getTurret().setHoodPos(hoodPosition);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
private void updateTelemetry(Pose p) {
|
||||
telemetry.addData("Avg FPS", "%.2f", fpsCounter.getAverageFps());
|
||||
|
||||
@@ -278,7 +262,7 @@ public class finalTeleOp {
|
||||
telemetry.addLine("▰▰▰▰▰▰▰ TRACKING ▰▰▰▰▰▰▰");
|
||||
telemetry.addData("Pose", "X:%.1f Y:%.1f H:%.1f°", p.getX(), p.getY(), Math.toDegrees(p.getHeading()));
|
||||
telemetry.addData("Distance", "%.1f in", stateMachine.getTurret().getDistance());
|
||||
telemetry.addData("Turret Ready", stateMachine.getTurret().isTurretReady());
|
||||
telemetry.addData("Turret Ready", stateMachine.getTurret().isTurretReady(false));
|
||||
telemetry.addData("Hood Offset", stateMachine.getTurret().offsetHood);
|
||||
|
||||
|
||||
|
||||
@@ -20,15 +20,16 @@ public class GetDistanceTuning extends OpMode {
|
||||
|
||||
private Limelight3A limelight;
|
||||
private double distance;
|
||||
public static double CAMERA_HEIGHT_INCHES = 12.5;
|
||||
|
||||
public static double CAMERA_HEIGHT_INCHES = 12.75;
|
||||
public static double GOAL_HEIGHT_INCHES = 29.5;
|
||||
public static int pipeline = 1;
|
||||
public static double CAMERA_MOUNT_ANGLE_DEGREES = 14.3;
|
||||
public static double CAMERA_MOUNT_ANGLE_DEGREES = 19.8;
|
||||
|
||||
public static double TARGET_DISTANCE = 0.0;
|
||||
|
||||
private TelemetryManager telemetryM;
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
limelight = hardwareMap.get(Limelight3A.class, "limelight");
|
||||
@@ -49,14 +50,22 @@ public class GetDistanceTuning extends OpMode {
|
||||
double targetY = result.getTy();
|
||||
double targetArea = result.getTa();
|
||||
|
||||
if (TARGET_DISTANCE != 0) {
|
||||
double requiredAngleRadians = Math.atan((GOAL_HEIGHT_INCHES - CAMERA_HEIGHT_INCHES) / TARGET_DISTANCE);
|
||||
CAMERA_MOUNT_ANGLE_DEGREES = Math.toDegrees(requiredAngleRadians) - targetY;
|
||||
|
||||
telemetryM.debug("Mode", "Angle Auto-Tuning (Diff Mode)");
|
||||
} else {
|
||||
telemetryM.debug("Mode", "Standard");
|
||||
}
|
||||
|
||||
distance = getTrigBasedDistance(targetY);
|
||||
|
||||
double areaDistance = getDistanceFromTag(targetArea);
|
||||
|
||||
telemetryM.debug("Method", "Trigonometry");
|
||||
telemetryM.debug("Target Y (ty)", targetY);
|
||||
telemetryM.debug("Calculated Distance", distance);
|
||||
telemetryM.debug("Camera Mount Angle", CAMERA_MOUNT_ANGLE_DEGREES);
|
||||
|
||||
telemetryM.debug("Area Algo Distance", areaDistance);
|
||||
|
||||
@@ -71,13 +80,7 @@ public class GetDistanceTuning extends OpMode {
|
||||
}
|
||||
|
||||
private double getTrigBasedDistance(double targetOffsetAngleVertical) {
|
||||
|
||||
return (GOAL_HEIGHT_INCHES - CAMERA_HEIGHT_INCHES) / Math.tan(Math.toRadians(CAMERA_MOUNT_ANGLE_DEGREES + targetOffsetAngleVertical));
|
||||
|
||||
// Calculate distance
|
||||
//double distanceFromLimelightToGoalInches = (GOAL_HEIGHT_INCHES - CAMERA_HEIGHT_INCHES) / Math.tan(angleToGoalRadians);
|
||||
|
||||
//return distanceFromLimelightToGoalInches;
|
||||
}
|
||||
|
||||
private double getDistanceFromTag(double x) {
|
||||
|
||||
@@ -30,11 +30,11 @@ public class PIDFTuning extends OpMode {
|
||||
public void init() {
|
||||
flywheelMotorR = hardwareMap.get(DcMotorEx.class, "rturret");
|
||||
flywheelMotorR.setMode(DcMotor.RunMode.RUN_USING_ENCODER);
|
||||
flywheelMotorR.setDirection(DcMotorSimple.Direction.REVERSE);
|
||||
flywheelMotorR.setDirection(DcMotorSimple.Direction.FORWARD);
|
||||
|
||||
flywheelMotorR = hardwareMap.get(DcMotorEx.class, "rturret");
|
||||
flywheelMotorR.setMode(DcMotor.RunMode.RUN_USING_ENCODER);
|
||||
flywheelMotorR.setDirection(reverse ? DcMotorSimple.Direction.REVERSE : DcMotorSimple.Direction.FORWARD);
|
||||
flywheelMotorL = hardwareMap.get(DcMotorEx.class, "lturret");
|
||||
flywheelMotorL.setMode(DcMotor.RunMode.RUN_USING_ENCODER);
|
||||
flywheelMotorL.setDirection(reverse ? DcMotorSimple.Direction.REVERSE : DcMotorSimple.Direction.FORWARD);
|
||||
|
||||
telemetry.addLine("Init complete");
|
||||
}
|
||||
|
||||
@@ -27,8 +27,8 @@ public class TurretRotationTuning extends LinearOpMode {
|
||||
public static double MAX_INTEGRAL = 0.5;
|
||||
|
||||
// --- MECHANICAL CONSTANTS ---
|
||||
public static double TICKS_PER_REV_MOTOR = 384.5;
|
||||
public static double EXTERNAL_GEAR_RATIO = 2.68888889;
|
||||
public static double TICKS_PER_REV_MOTOR = 145.1;
|
||||
public static double EXTERNAL_GEAR_RATIO = 9.179875;
|
||||
public static boolean MOTOR_REVERSED = true;
|
||||
|
||||
// --- CALIBRATION SETTINGS ---
|
||||
@@ -117,8 +117,6 @@ public class TurretRotationTuning extends LinearOpMode {
|
||||
break;
|
||||
}
|
||||
|
||||
sleep(fps.getSyncTime(targetFPS));
|
||||
|
||||
// --- TELEMETRY ---
|
||||
telemetryM.debug("▰▰▰▰▰ MODE ▰▰▰▰▰", currentMode.toString());
|
||||
telemetryM.debug("Gear Ratio", EXTERNAL_GEAR_RATIO);
|
||||
@@ -128,6 +126,8 @@ public class TurretRotationTuning extends LinearOpMode {
|
||||
telemetryM.debug("Target Deg", targetTicks / ticksPerDegree);
|
||||
telemetry.addData("FPS", fps.getAverageFps());
|
||||
telemetryM.update(telemetry);
|
||||
|
||||
sleep(fps.getSyncTime(targetFPS));
|
||||
}
|
||||
limelight.stop();
|
||||
}
|
||||
|
||||
@@ -336,7 +336,7 @@ public class allInOne extends LinearOpMode {
|
||||
double ta = result.getTa();
|
||||
calculatedDistance = getDistanceFromTag(ta);
|
||||
calculatedVelocity = getFlywheelVelocity(calculatedDistance);
|
||||
calculatedHoodPos = getHoodPOS(calculatedDistance, calculatedVelocity);
|
||||
calculatedHoodPos = getHoodPOS(calculatedDistance);
|
||||
|
||||
if (launch) {
|
||||
leftTurret.setVelocity(calculatedVelocity);
|
||||
@@ -459,7 +459,7 @@ public class allInOne extends LinearOpMode {
|
||||
return (0.0000119972 * Math.pow((dist), 4) - 0.00249603 * Math.pow(dist, 3) + 0.179513 * Math.pow(dist, 2) + (0.0519688 * dist) + 1489.8908);
|
||||
}
|
||||
|
||||
private double getHoodPOS(double dist, double targetVelocity) {
|
||||
return Range.clip(((-(5.15893 * Math.pow(10, -8)) * Math.pow(dist, 4)) + 0.00000954719 * Math.pow(dist, 3) - (0.000349083 * Math.pow(dist, 2)) + (-0.0153896 * dist) + 1.37618 + calculateHoodOffset(targetVelocity)), SERVO_MIN, SERVO_MAX);
|
||||
private double getHoodPOS(double dist) {
|
||||
return ((-(8.57654 * Math.pow(10, -9)) * Math.pow(dist, 4)) + (0.00000166094 * Math.pow(dist, 3)) - (0.0000796795 * Math.pow(dist, 2)) + (-0.00326804 * dist) + 0.433859);
|
||||
}
|
||||
}
|
||||
@@ -83,8 +83,6 @@ public class anchorTuning extends LinearOpMode {
|
||||
driveTrain.teleopDrive(gamepad1.left_stick_x, -gamepad1.left_stick_y, gamepad1.right_stick_x);
|
||||
}
|
||||
|
||||
sleep(fps.getSyncTime(targetFPS));
|
||||
|
||||
telemetryM.debug("Anchor Active", driveTrain.isAnchorActive());
|
||||
|
||||
telemetry.addData("FPS", fps.getAverageFps());
|
||||
@@ -94,6 +92,8 @@ public class anchorTuning extends LinearOpMode {
|
||||
telemetryM.debug("Error TRN (Degs)", driveTrain.getLastTurnError());
|
||||
|
||||
telemetryM.update(telemetry);
|
||||
|
||||
sleep(fps.getSyncTime(targetFPS));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -223,8 +223,8 @@ public class autoCollection extends LinearOpMode {
|
||||
break;
|
||||
}
|
||||
|
||||
sleep(fpsCounter.getSyncTime(targetFPS));
|
||||
updateTelemetry(currentTicks, currentDegrees);
|
||||
sleep(fpsCounter.getSyncTime(targetFPS));
|
||||
}
|
||||
limelight.stop();
|
||||
}
|
||||
|
||||
@@ -1,37 +1,74 @@
|
||||
package org.firstinspires.ftc.teamcode.tuning;
|
||||
|
||||
import com.bylazar.configurables.annotations.Configurable;
|
||||
import com.bylazar.telemetry.PanelsTelemetry;
|
||||
import com.qualcomm.hardware.limelightvision.LLResult;
|
||||
import com.qualcomm.hardware.limelightvision.Limelight3A;
|
||||
import com.qualcomm.robotcore.eventloop.opmode.OpMode;
|
||||
import com.qualcomm.robotcore.eventloop.opmode.TeleOp;
|
||||
import com.qualcomm.robotcore.hardware.DcMotor;
|
||||
import com.qualcomm.robotcore.hardware.DcMotorEx;
|
||||
import com.qualcomm.robotcore.hardware.DcMotorSimple;
|
||||
import com.qualcomm.robotcore.hardware.PIDFCoefficients;
|
||||
import com.qualcomm.robotcore.hardware.Servo;
|
||||
import com.qualcomm.robotcore.util.Range;
|
||||
|
||||
// Make sure your import points to your actual Constants file
|
||||
import org.firstinspires.ftc.teamcode.teleOp.Constants;
|
||||
|
||||
import com.bylazar.telemetry.TelemetryManager;
|
||||
|
||||
@Configurable
|
||||
@TeleOp
|
||||
public class flywheelTuning extends OpMode {
|
||||
|
||||
public enum CalibrationState {
|
||||
IDLE,
|
||||
SPOOLING,
|
||||
TRACKING,
|
||||
TUNING
|
||||
}
|
||||
|
||||
private Limelight3A limelight;
|
||||
|
||||
public DcMotorEx flywheelMotorR;
|
||||
public DcMotorEx flywheelMotorL;
|
||||
|
||||
public Servo hoodServo;
|
||||
public DcMotor intake;
|
||||
|
||||
public Servo hoodServo;
|
||||
public Servo limiter;
|
||||
|
||||
public static boolean autoMode = false;
|
||||
public static double curTargetVelocity = 0;
|
||||
public static double targetPOS = 0;
|
||||
public static int pipeline = 1;
|
||||
|
||||
public static boolean reverse = false;
|
||||
public static boolean reverse = true;
|
||||
|
||||
double distance = 0;
|
||||
|
||||
CalibrationState calibState = CalibrationState.IDLE;
|
||||
boolean lastX = false;
|
||||
|
||||
double maxError = 0.0;
|
||||
double snapshotAutoHood = 0.0;
|
||||
double calculatedGain = 0.0;
|
||||
|
||||
public static double P = 1.3;
|
||||
public static double I = 0;
|
||||
public static double D = 2;
|
||||
public static double F = 13.5;
|
||||
|
||||
private double lastP = P;
|
||||
private double lastI = I;
|
||||
private double lastD = D;
|
||||
private double lastF = F;
|
||||
|
||||
public static double distanceOffset = 0.0;
|
||||
|
||||
private TelemetryManager telemetryM;
|
||||
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
flywheelMotorR = hardwareMap.get(DcMotorEx.class, Constants.TurretConstants.TURRET_RIGHT_MOTOR);
|
||||
@@ -42,46 +79,219 @@ public class flywheelTuning extends OpMode {
|
||||
flywheelMotorL.setMode(DcMotorEx.RunMode.RUN_USING_ENCODER);
|
||||
flywheelMotorL.setDirection(reverse ? DcMotorSimple.Direction.FORWARD : DcMotorSimple.Direction.REVERSE);
|
||||
|
||||
flywheelMotorR.setPIDFCoefficients(DcMotor.RunMode.RUN_USING_ENCODER, new PIDFCoefficients(P, I, D, F));
|
||||
flywheelMotorL.setPIDFCoefficients(DcMotor.RunMode.RUN_USING_ENCODER, new PIDFCoefficients(P, I, D, F));
|
||||
hoodServo = hardwareMap.servo.get("hoodservo");
|
||||
|
||||
hoodServo.setDirection(Servo.Direction.REVERSE);
|
||||
|
||||
limelight = hardwareMap.get(Limelight3A.class, "limelight");
|
||||
limelight.pipelineSwitch(pipeline);
|
||||
limelight.start();
|
||||
|
||||
intake = hardwareMap.get(DcMotor.class, "intake");
|
||||
intake.setDirection(DcMotorSimple.Direction.FORWARD);
|
||||
intake.setZeroPowerBehavior(DcMotor.ZeroPowerBehavior.BRAKE);
|
||||
|
||||
limiter = hardwareMap.servo.get("limiter");
|
||||
limiter.setDirection(Servo.Direction.FORWARD);
|
||||
|
||||
limiter.setPosition(1);
|
||||
|
||||
telemetryM = PanelsTelemetry.INSTANCE.getTelemetry();
|
||||
|
||||
telemetry.addLine("Init complete");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loop() {
|
||||
limelight.pipelineSwitch(pipeline);
|
||||
|
||||
LLResult result = limelight.getLatestResult();
|
||||
|
||||
if (result.isValid()) {
|
||||
if (result != null && result.isValid()) {
|
||||
double targetY = result.getTy();
|
||||
telemetry.addData("Ty", targetY);
|
||||
distance = getTrigBasedDistance(targetY);
|
||||
distance = getTrigBasedDistance(targetY) - distanceOffset;
|
||||
}
|
||||
|
||||
if (!gamepad1.b) {flywheelMotorR.setVelocity(curTargetVelocity);
|
||||
flywheelMotorL.setVelocity(curTargetVelocity);}
|
||||
boolean currentX = gamepad1.x;
|
||||
if (currentX && !lastX) {
|
||||
switch (calibState) {
|
||||
case IDLE:
|
||||
maxError = 0.0;
|
||||
calculatedGain = 0.0;
|
||||
calibState = CalibrationState.SPOOLING;
|
||||
break;
|
||||
case SPOOLING:
|
||||
calibState = CalibrationState.TRACKING;
|
||||
break;
|
||||
case TRACKING:
|
||||
snapshotAutoHood = getHoodPOS(distance);
|
||||
calibState = CalibrationState.TUNING;
|
||||
break;
|
||||
case TUNING:
|
||||
calibState = CalibrationState.IDLE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
lastX = currentX;
|
||||
|
||||
hoodServo.setPosition(Range.clip(targetPOS, Constants.TurretConstants.SERVO_MIN, Constants.TurretConstants.SERVO_MAX));
|
||||
double applyVel = 0;
|
||||
double applyHood = 0;
|
||||
double currentVel = flywheelMotorR.getVelocity();
|
||||
|
||||
double autoTargetVel = getFlywheelVelocity(distance);
|
||||
double autoHoodPos = getHoodPOS(distance);
|
||||
|
||||
|
||||
if (P != lastP || I != lastI || D != lastD || F != lastF) {
|
||||
PIDFCoefficients newCoefficients = new PIDFCoefficients(P, I, D, F);
|
||||
flywheelMotorR.setPIDFCoefficients(DcMotor.RunMode.RUN_USING_ENCODER, newCoefficients);
|
||||
flywheelMotorL.setPIDFCoefficients(DcMotor.RunMode.RUN_USING_ENCODER, newCoefficients);
|
||||
|
||||
telemetry.addData("Current Velocity", "Current Velocity: %.2f", flywheelMotorL.getVelocity());
|
||||
telemetry.addData("Target Velocity", "Target Velocity: %.2f", curTargetVelocity);
|
||||
telemetry.addData("Target Position", "Target Velocity: %.2f", targetPOS);
|
||||
telemetry.addData("Distance", distance);
|
||||
lastP = P;
|
||||
lastI = I;
|
||||
lastD = D;
|
||||
lastF = F;
|
||||
}
|
||||
|
||||
|
||||
if (autoMode) {
|
||||
switch (calibState) {
|
||||
case IDLE:
|
||||
applyVel = autoTargetVel;
|
||||
applyHood = autoHoodPos;
|
||||
break;
|
||||
|
||||
case SPOOLING:
|
||||
applyVel = autoTargetVel;
|
||||
applyHood = autoHoodPos;
|
||||
if (Math.abs(currentVel - autoTargetVel) <= 30) {
|
||||
calibState = CalibrationState.TRACKING;
|
||||
}
|
||||
break;
|
||||
|
||||
case TRACKING:
|
||||
applyVel = autoTargetVel;
|
||||
applyHood = autoHoodPos;
|
||||
|
||||
double currentError = currentVel - autoTargetVel;
|
||||
if (currentError < maxError) {
|
||||
maxError = currentError;
|
||||
}
|
||||
break;
|
||||
|
||||
case TUNING:
|
||||
applyVel = autoTargetVel + maxError;
|
||||
|
||||
applyHood = targetPOS;
|
||||
|
||||
if (maxError != 0) {
|
||||
calculatedGain = (targetPOS - snapshotAutoHood) / maxError;
|
||||
} else {
|
||||
calculatedGain = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
applyVel = curTargetVelocity;
|
||||
applyHood = targetPOS;
|
||||
}
|
||||
|
||||
if (!gamepad1.b) {
|
||||
flywheelMotorR.setVelocity(applyVel);
|
||||
flywheelMotorL.setVelocity(applyVel);
|
||||
} else {
|
||||
flywheelMotorR.setVelocity(0);
|
||||
flywheelMotorL.setVelocity(0);
|
||||
}
|
||||
|
||||
if (gamepad1.a) {
|
||||
intake.setPower(1);
|
||||
limiter.setPosition(0.82);
|
||||
} else {
|
||||
limiter.setPosition(1);
|
||||
intake.setPower(0);
|
||||
}
|
||||
|
||||
double recoilOffset = (currentVel - applyVel) * -0.000185;
|
||||
|
||||
hoodServo.setPosition(Range.clip(applyHood + recoilOffset, Constants.TurretConstants.SERVO_MIN, Constants.TurretConstants.SERVO_MAX));
|
||||
|
||||
telemetry.addData("Operating Mode", autoMode ? "AUTOMATIC" : "MANUAL");
|
||||
telemetry.addData("Calibration State", calibState.toString());
|
||||
telemetry.addLine();
|
||||
|
||||
telemetry.addData("Current Velocity", "%.2f", currentVel);
|
||||
telemetry.addData("Applied Target Vel", "%.2f", applyVel);
|
||||
telemetry.addData("Applied Target Hood", "%.4f", applyHood);
|
||||
telemetry.addData("Distance", "%.2f inches", distance);
|
||||
telemetry.addLine();
|
||||
|
||||
telemetryM.addData("Current Velocity", currentVel);
|
||||
|
||||
if (autoMode) {
|
||||
telemetry.addData("Raw Auto Target Vel", "%.2f", autoTargetVel);
|
||||
telemetry.addData("Raw Auto Target Hood", "%.4f", autoHoodPos);
|
||||
telemetry.addLine("--- CALIBRATION DATA ---");
|
||||
telemetry.addData("Max RPM Drop (Error)", "%.2f", maxError);
|
||||
telemetry.addData("Snapshot Auto Hood", "%.4f", snapshotAutoHood);
|
||||
telemetry.addData("User Tuning Hood (targetPOS)", "%.4f", targetPOS);
|
||||
telemetry.addData("CALCULATED GAIN", "%.8f", calculatedGain);
|
||||
telemetry.addLine("NOTE: When done tuning, copy CALCULATED GAIN into your snippet!");
|
||||
}
|
||||
|
||||
telemetry.update();
|
||||
telemetryM.update(telemetry);
|
||||
}
|
||||
|
||||
private double getTrigBasedDistance(double targetOffsetAngleVertical) {
|
||||
return (17.1) / Math.tan(Math.toRadians(7.9 + targetOffsetAngleVertical));
|
||||
// ^ GOAL - CAMERA HEIGHT ^ Offset Degrees
|
||||
return (29.5-12.75) / Math.tan(Math.toRadians(19.8 + targetOffsetAngleVertical));
|
||||
// ^ GOAL - CAMERA HEIGHT ^ Offset Degrees
|
||||
}
|
||||
|
||||
private double getFlywheelVelocity(double dist) {
|
||||
if (dist <= 0) return 0;
|
||||
|
||||
if (dist < 19.0) {
|
||||
return 1300.0;
|
||||
}
|
||||
|
||||
if (dist > 145.0) {
|
||||
return 2300.0;
|
||||
}
|
||||
|
||||
double x = dist;
|
||||
double x2 = x * x;
|
||||
double x3 = x2 * x;
|
||||
double x4 = x3 * x;
|
||||
|
||||
double velocity = (-0.0000218345 * x4)
|
||||
+ (0.00636447 * x3)
|
||||
+ (-0.593959 * x2)
|
||||
+ (26.08276 * x)
|
||||
+ 1218.12895;
|
||||
|
||||
return Range.clip(velocity, 1300.0, 2350.0);
|
||||
}
|
||||
private double getHoodPOS(double dist) {
|
||||
if (dist < 20.0) {
|
||||
return 0.36;
|
||||
}
|
||||
|
||||
if (dist > 125.0) {
|
||||
return 0.09;
|
||||
}
|
||||
double x = dist;
|
||||
double x2 = x * x;
|
||||
double x3 = x2 * x;
|
||||
double x4 = x3 * x;
|
||||
|
||||
double hoodPos = (5.34037e-9 * x4)
|
||||
+ (-1.70158e-6 * x3)
|
||||
+ (2.04794e-4 * x2)
|
||||
+ (-0.013153 * x)
|
||||
+ 0.55256;
|
||||
|
||||
return Range.clip(hoodPos, Constants.TurretConstants.SERVO_MIN, Constants.TurretConstants.SERVO_MAX);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package org.firstinspires.ftc.teamcode.tuning;
|
||||
|
||||
import com.qualcomm.robotcore.eventloop.opmode.OpMode;
|
||||
import com.qualcomm.robotcore.eventloop.opmode.TeleOp;
|
||||
import com.qualcomm.robotcore.hardware.ServoImplEx;
|
||||
import com.qualcomm.robotcore.hardware.PwmControl;
|
||||
import com.bylazar.configurables.annotations.Configurable;
|
||||
|
||||
@Configurable
|
||||
@TeleOp(name = "GoBilda RGB Indicator Test", group = "Tests")
|
||||
public class ledTest extends OpMode {
|
||||
|
||||
// Declare the light as a ServoImplEx
|
||||
private ServoImplEx rgbLight;
|
||||
|
||||
public static double LED1 = 0.33;
|
||||
public static double LED2 = 0.66;
|
||||
public static double LED3 = 0.99;
|
||||
|
||||
private boolean lightOn = false;
|
||||
|
||||
private double lightPosition = 0;
|
||||
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
rgbLight = hardwareMap.get(ServoImplEx.class, "prism");
|
||||
|
||||
rgbLight.setPwmRange(new PwmControl.PwmRange(500, 2500));
|
||||
|
||||
telemetry.addData("Status", "Initialized. Ready to test colors.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loop() {
|
||||
|
||||
if (gamepad1.psWasPressed()) {
|
||||
lightOn = !lightOn;
|
||||
}
|
||||
|
||||
if (gamepad1.a) {
|
||||
lightPosition = LED1;
|
||||
}
|
||||
else if (gamepad1.b) {
|
||||
lightPosition = 0;
|
||||
}
|
||||
else if (gamepad1.x) {
|
||||
lightPosition = LED2;
|
||||
}
|
||||
else if (gamepad1.y) {
|
||||
lightPosition = LED3;
|
||||
}
|
||||
|
||||
if (gamepad1.right_trigger > 0.1) {
|
||||
lightPosition = gamepad1.right_trigger;
|
||||
}
|
||||
|
||||
if (lightOn) {
|
||||
rgbLight.setPwmEnable();
|
||||
} else {
|
||||
rgbLight.setPwmDisable();
|
||||
}
|
||||
|
||||
rgbLight.setPosition(lightPosition);
|
||||
|
||||
telemetry.addData("Current Light Position", rgbLight.getPosition());
|
||||
telemetry.update();
|
||||
}
|
||||
}
|
||||
@@ -23,38 +23,40 @@ import java.util.List;
|
||||
@TeleOp(name = "Odo Turret Tracking", group = "Turret")
|
||||
public class odoTracking extends LinearOpMode {
|
||||
|
||||
public static double kP = 0.02;
|
||||
public static double kI = 0.0;
|
||||
public static double kD = 0.001;
|
||||
public static double kP = 0.0040;
|
||||
public static double kI = 0.002;
|
||||
public static double kD = 0.0004;
|
||||
public static double MAX_POWER = 0.6;
|
||||
public static double MAX_INTEGRAL = 0.5;
|
||||
|
||||
// ================= Hardware Constants =================
|
||||
public static double TICKS_PER_REV_MOTOR = 384.5;
|
||||
public static double EXTERNAL_GEAR_RATIO = 2.68888889;
|
||||
public static boolean MOTOR_REVERSED = true;
|
||||
public static double TICKS_PER_REV_MOTOR = 145.1;
|
||||
public static double EXTERNAL_GEAR_RATIO = 9.179875;
|
||||
public static boolean MOTOR_REVERSED = false;
|
||||
|
||||
// ================= Limits & Logic =================
|
||||
public static double LL_LOGIC_MULTIPLIER = 1.0;
|
||||
public static double SOFT_LIMIT_NEG = -230;
|
||||
public static double SOFT_LIMIT_POS = 230;
|
||||
public static double LL_LOGIC_MULTIPLIER = -1.0;
|
||||
public static double SOFT_LIMIT_NEG = -330;
|
||||
public static double SOFT_LIMIT_POS = 350;
|
||||
|
||||
// ================= Targeting Offsets =================
|
||||
public static double RED_TARGET_OFFSET_DEGREES = 14;
|
||||
public static double BLUE_TARGET_OFFSET_DEGREES = 17;
|
||||
public static double LL_TARGET_OFFSET_DEGREES = -2;
|
||||
public static double RED_TARGET_OFFSET_DEGREES = 0;
|
||||
public static double BLUE_TARGET_OFFSET_DEGREES = 0;
|
||||
public static double LL_TARGET_OFFSET_DEGREES = 0;
|
||||
|
||||
// ================= Field Coordinates =================
|
||||
public static double GOAL_RED_X = 138;
|
||||
public static double GOAL_RED_Y = 138;
|
||||
public static double GOAL_BLUE_X = 6;
|
||||
public static double GOAL_BLUE_Y = 138;
|
||||
public static double GOAL_RED_X = 140;
|
||||
public static double GOAL_RED_Y = 140;
|
||||
public static double GOAL_BLUE_X = 4;
|
||||
public static double GOAL_BLUE_Y = 140;
|
||||
|
||||
// ================= Sensor Fusion Settings =================
|
||||
public static double OFFSET_SMOOTHING = 0.2;
|
||||
|
||||
public static int targetFPS = 100;
|
||||
|
||||
public static double TURRET_FULL_WRAP_TICKS = 1340.0;
|
||||
|
||||
// ================= Hardware Objects =================
|
||||
private Limelight3A limelight;
|
||||
private DcMotorEx turretMotor;
|
||||
@@ -68,7 +70,6 @@ public class odoTracking extends LinearOpMode {
|
||||
|
||||
private double targetCorrectionOffsetTicks = 0;
|
||||
private double fusedTargetTicks = 0;
|
||||
|
||||
private enum TuningMode { CALIBRATION, TRACKING }
|
||||
private TuningMode currentMode = TuningMode.CALIBRATION;
|
||||
|
||||
@@ -80,7 +81,7 @@ public class odoTracking extends LinearOpMode {
|
||||
protected FPSCounter fpsCounter = new FPSCounter();
|
||||
|
||||
public static double start_x = 72;
|
||||
public static double start_y = 8.5;
|
||||
public static double start_y = 72;
|
||||
public static double start_heading = 90;
|
||||
|
||||
|
||||
@@ -157,48 +158,65 @@ public class odoTracking extends LinearOpMode {
|
||||
break;
|
||||
}
|
||||
|
||||
sleep(fpsCounter.getSyncTime(targetFPS));
|
||||
updateTelemetry(currentTicks, currentDegrees);
|
||||
sleep(fpsCounter.getSyncTime(targetFPS));
|
||||
}
|
||||
limelight.stop();
|
||||
}
|
||||
|
||||
private void calculateHybridTarget(double currentTicks, double currentDegrees) {
|
||||
double odoTargetTicks = calculateOdometryTargetTicks();
|
||||
Pose robotPose = follower.getPose();
|
||||
double odoTargetTicks = calculateOdometryTargetTicks(robotPose);
|
||||
|
||||
LLResult result = limelight.getLatestResult();
|
||||
|
||||
if (result != null && result.isValid()) {
|
||||
double rawErrorTicks = getErrorTicks(currentDegrees, result, odoTargetTicks);
|
||||
// 1. Calculate Vision Truth: Where the goal sits based on the camera right now
|
||||
double tx = result.getTx();
|
||||
double visionTargetDegrees = currentDegrees + (tx * LL_LOGIC_MULTIPLIER);
|
||||
double finalVisionDegrees = visionTargetDegrees + LL_TARGET_OFFSET_DEGREES;
|
||||
double visionTargetTicks = finalVisionDegrees * ticksPerDegree;
|
||||
|
||||
targetCorrectionOffsetTicks = (targetCorrectionOffsetTicks * (1.0 - OFFSET_SMOOTHING))
|
||||
+ (rawErrorTicks * OFFSET_SMOOTHING);
|
||||
// 2. Calculate Current Fused Target: Where we currently think the goal is (Odo + existing Offset)
|
||||
double currentFusedTarget = odoTargetTicks + targetCorrectionOffsetTicks;
|
||||
|
||||
// 3. Calculate Correction Error: The delta between our current belief and camera reality
|
||||
double correctionError = visionTargetTicks - currentFusedTarget;
|
||||
|
||||
// 4. Normalize the error for wrapping (360 degrees)
|
||||
double ticksPerRev = 360.0 * ticksPerDegree;
|
||||
while (correctionError > (ticksPerRev / 2)) correctionError -= ticksPerRev;
|
||||
while (correctionError < -(ticksPerRev / 2)) correctionError += ticksPerRev;
|
||||
|
||||
// 5. Apply the error to the persistent offset (Bias-Shift)
|
||||
// We use OFFSET_SMOOTHING as a gain to prevent single-frame noise from causing jitter
|
||||
targetCorrectionOffsetTicks += (correctionError * OFFSET_SMOOTHING);
|
||||
}
|
||||
|
||||
double rawTarget = odoTargetTicks + targetCorrectionOffsetTicks;
|
||||
|
||||
fusedTargetTicks = Range.clip(rawTarget, SOFT_LIMIT_NEG, SOFT_LIMIT_POS);
|
||||
// 1. Apply initial soft limits
|
||||
double preWrapTarget = Range.clip(rawTarget, SOFT_LIMIT_NEG, SOFT_LIMIT_POS);
|
||||
|
||||
// 2. Implement wrapping logic: if target exceeds 180 degrees (670 ticks), normalize to the other side.
|
||||
// This implies a full wrap cycle is 2 * 670 = 1340 ticks.
|
||||
double fullWrapTicks = TURRET_FULL_WRAP_TICKS;
|
||||
double halfWrapTicks = fullWrapTicks / 2.0;
|
||||
|
||||
// If target is beyond positive half-wrap threshold, wrap to negative equivalent
|
||||
if (preWrapTarget > halfWrapTicks) {
|
||||
preWrapTarget -= fullWrapTicks;
|
||||
}
|
||||
// If target is beyond negative half-wrap threshold, wrap to positive equivalent
|
||||
else if (preWrapTarget < -halfWrapTicks) {
|
||||
preWrapTarget += fullWrapTicks;
|
||||
}
|
||||
|
||||
// 3. Apply final soft limits after wrapping
|
||||
fusedTargetTicks = Range.clip(preWrapTarget, SOFT_LIMIT_NEG, SOFT_LIMIT_POS);
|
||||
}
|
||||
|
||||
private double getErrorTicks(double currentDegrees, LLResult result, double odoTargetTicks) {
|
||||
double tx = result.getTx();
|
||||
|
||||
double visionTargetDegrees = currentDegrees + (tx * LL_LOGIC_MULTIPLIER);
|
||||
|
||||
double finalVisionDegrees = visionTargetDegrees + LL_TARGET_OFFSET_DEGREES;
|
||||
double visionTargetTicks = finalVisionDegrees * ticksPerDegree;
|
||||
|
||||
double rawErrorTicks = visionTargetTicks - odoTargetTicks;
|
||||
|
||||
double ticksPerRev = 360.0 * ticksPerDegree;
|
||||
|
||||
while (rawErrorTicks > (ticksPerRev / 2)) rawErrorTicks -= ticksPerRev;
|
||||
while (rawErrorTicks < -(ticksPerRev / 2)) rawErrorTicks += ticksPerRev;
|
||||
return rawErrorTicks;
|
||||
}
|
||||
|
||||
private double calculateOdometryTargetTicks() {
|
||||
Pose robotPose = follower.getPose();
|
||||
private double calculateOdometryTargetTicks(Pose robotPose) {
|
||||
double targetX = (currentAlliance == Alliance.RED) ? GOAL_RED_X : GOAL_BLUE_X;
|
||||
double targetY = (currentAlliance == Alliance.RED) ? GOAL_RED_Y : GOAL_BLUE_Y;
|
||||
|
||||
@@ -237,6 +255,7 @@ public class odoTracking extends LinearOpMode {
|
||||
|
||||
double output = (kP * error) + integralTerm + (kD * derivative);
|
||||
output = Range.clip(output, -MAX_POWER, MAX_POWER);
|
||||
telemetry.addData("Power", output);
|
||||
|
||||
turretMotor.setPower(output);
|
||||
lastError = error;
|
||||
|
||||
@@ -3,7 +3,7 @@ package org.firstinspires.ftc.teamcode.util;
|
||||
import com.qualcomm.robotcore.util.ElapsedTime;
|
||||
|
||||
public class FPSCounter {
|
||||
private ElapsedTime loopTimer = new ElapsedTime();
|
||||
private final ElapsedTime loopTimer = new ElapsedTime();
|
||||
private double loopTimeSum = 0;
|
||||
private int loopCount = 0;
|
||||
private double currentLoopTime = 0;
|
||||
@@ -13,6 +13,9 @@ public class FPSCounter {
|
||||
reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this at the very beginning of your while(opModeIsActive) loop.
|
||||
*/
|
||||
public void startLoop() {
|
||||
double now = loopTimer.milliseconds();
|
||||
if (loopCount > 0) {
|
||||
@@ -23,10 +26,17 @@ public class FPSCounter {
|
||||
loopCount++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the time remaining to hit the target FPS.
|
||||
* To be accurate, call this at the very end of your loop,
|
||||
* AFTER telemetry.update().
|
||||
*/
|
||||
public long getSyncTime(int targetFps) {
|
||||
if (targetFps <= 0) return 0;
|
||||
|
||||
double targetMs = 1000.0 / targetFps;
|
||||
|
||||
double elapsedWorkMs = loopTimer.milliseconds() - lastTime;
|
||||
double now = loopTimer.milliseconds();
|
||||
double elapsedWorkMs = now - lastTime;
|
||||
double remainingMs = targetMs - elapsedWorkMs;
|
||||
|
||||
return (remainingMs > 0) ? (long) remainingMs : 0;
|
||||
@@ -57,4 +67,4 @@ public class FPSCounter {
|
||||
loopCount = 0;
|
||||
currentLoopTime = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,12 @@ android.useAndroidX=true
|
||||
android.enableJetifier=false
|
||||
|
||||
# Allow Gradle to use up to 1 GB of RAM
|
||||
org.gradle.jvmargs=-Xmx1024M
|
||||
org.gradle.jvmargs=-Xmx2048M
|
||||
|
||||
android.nonTransitiveRClass=false
|
||||
org.gradle.configuration-cache=true
|
||||
org.gradle.configuration-cache=true
|
||||
|
||||
org.gradle.parallel=true
|
||||
org.gradle.caching=true
|
||||
|
||||
org.gradle.daemon=true
|
||||
Reference in New Issue
Block a user