diff --git a/FtcRobotController/build.gradle b/FtcRobotController/build.gradle index 9fa2169..8c796da 100644 --- a/FtcRobotController/build.gradle +++ b/FtcRobotController/build.gradle @@ -17,8 +17,8 @@ android { buildFeatures { buildConfig = true } + compileSdk 34 - compileSdkVersion 30 compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 diff --git a/TeamCode/src/main/java/org/firstinspires/ftc/teamcode/autonomous/Blue.java b/TeamCode/src/main/java/org/firstinspires/ftc/teamcode/autonomous/Blue.java new file mode 100644 index 0000000..84087b5 --- /dev/null +++ b/TeamCode/src/main/java/org/firstinspires/ftc/teamcode/autonomous/Blue.java @@ -0,0 +1,478 @@ +package org.firstinspires.ftc.teamcode.autonomous; + +import static org.firstinspires.ftc.teamcode.constants.Poses.h1; +import static org.firstinspires.ftc.teamcode.constants.Poses.h2; +import static org.firstinspires.ftc.teamcode.constants.Poses.h2_b; +import static org.firstinspires.ftc.teamcode.constants.Poses.h3; +import static org.firstinspires.ftc.teamcode.constants.Poses.teleStart; +import static org.firstinspires.ftc.teamcode.constants.Poses.x1; +import static org.firstinspires.ftc.teamcode.constants.Poses.x2; +import static org.firstinspires.ftc.teamcode.constants.Poses.x2_b; +import static org.firstinspires.ftc.teamcode.constants.Poses.x3; +import static org.firstinspires.ftc.teamcode.constants.Poses.y1; +import static org.firstinspires.ftc.teamcode.constants.Poses.y2; +import static org.firstinspires.ftc.teamcode.constants.Poses.y2_b; +import static org.firstinspires.ftc.teamcode.constants.Poses.y3; +import static org.firstinspires.ftc.teamcode.constants.ServoPositions.*; + +import androidx.annotation.NonNull; + +import com.acmerobotics.dashboard.FtcDashboard; +import com.acmerobotics.dashboard.config.Config; +import com.acmerobotics.dashboard.telemetry.MultipleTelemetry; +import com.acmerobotics.dashboard.telemetry.TelemetryPacket; +import com.acmerobotics.roadrunner.Action; +import com.acmerobotics.roadrunner.ParallelAction; +import com.acmerobotics.roadrunner.Pose2d; +import com.acmerobotics.roadrunner.TrajectoryActionBuilder; +import com.acmerobotics.roadrunner.Vector2d; +import com.acmerobotics.roadrunner.ftc.Actions; +import com.qualcomm.robotcore.eventloop.opmode.Autonomous; +import com.qualcomm.robotcore.eventloop.opmode.LinearOpMode; + +import org.firstinspires.ftc.teamcode.libs.RR.MecanumDrive; +import org.firstinspires.ftc.teamcode.subsystems.AprilTag; +import org.firstinspires.ftc.teamcode.subsystems.Intake; +import org.firstinspires.ftc.teamcode.subsystems.Shooter; +import org.firstinspires.ftc.teamcode.subsystems.Spindexer; +import org.firstinspires.ftc.teamcode.subsystems.Transfer; +import org.firstinspires.ftc.teamcode.utils.Robot; + + +@Config +@Autonomous (preselectTeleOp = "TeleopV1") +public class Blue extends LinearOpMode { + + Robot robot; + + MultipleTelemetry TELE; + + MecanumDrive drive; + + AprilTag aprilTag; + + Shooter shooter; + + + + public static double angle = 0.1; + + Spindexer spindexer; + + Transfer transfer; + + public class shooterOn implements Action { + + int ticker = 1; + + double stamp = 0.0; + + + @Override + public boolean run(@NonNull TelemetryPacket telemetryPacket) { + + if (ticker ==1){ + stamp = getRuntime(); + + } + + ticker ++; + + if (getRuntime() - stamp < 0.2){ + return true; + } else if (getRuntime() - stamp < 0.4) { + + shooter.setManualPower(1); + + shooter.update(); + + return true; + } else { + + return false; + + } + } + } + + + + + + @Override + public void runOpMode() throws InterruptedException { + + + + + robot = new Robot(hardwareMap); + TELE = new MultipleTelemetry( + telemetry, FtcDashboard.getInstance().getTelemetry() + ); + + drive = new MecanumDrive(hardwareMap, new Pose2d( + 0,0,0 + )); + + aprilTag = new AprilTag(robot, TELE); + + shooter = new Shooter(robot, TELE); + + spindexer = new Spindexer(robot, TELE); + + spindexer.outtake3(); + + shooter.setShooterMode("MANUAL"); + + shooter.sethoodPosition(0.53); + + transfer = new Transfer(robot); + + transfer.setTransferPosition(transferServo_out); + + Intake intake = new Intake(robot); + + robot.hood.setPosition(hoodDefault); + + + + + + + + + TrajectoryActionBuilder traj1 = drive.actionBuilder(new Pose2d(0, 0, 0)) + .strafeToLinearHeading(new Vector2d(x1, y1), h1 ); + + + TrajectoryActionBuilder traj2 = drive.actionBuilder(new Pose2d(x1, y1, h1)) + .turnTo(Math.toRadians(-135)) + .strafeToLinearHeading(new Vector2d(x2, -y2), -h2 ); + + + TrajectoryActionBuilder traj3 = drive.actionBuilder(new Pose2d(x2, -y2, -h2)) + .strafeToLinearHeading(new Vector2d(x1, y1), h1 ); + + TrajectoryActionBuilder traj4 = drive.actionBuilder(new Pose2d(x1, y1, h1)) + + .strafeToLinearHeading(new Vector2d(x2_b, -y2_b), -h2_b ) + + .strafeToLinearHeading(new Vector2d(x3, -y3), -h3 ); + + + TrajectoryActionBuilder traj5 = drive.actionBuilder(new Pose2d(x3, -y3, -h3)) + .strafeToLinearHeading(new Vector2d(x1, y1), h1 ); + + + TrajectoryActionBuilder traj6 = drive.actionBuilder(new Pose2d(x1, y1, h1)) + .strafeToLinearHeading(new Vector2d(x1, y1-30), h1 ); + + while(opModeInInit()) { + + if (gamepad2.dpadUpWasPressed()){ + hoodDefault -= 0.02; + } + + if (gamepad2.dpadDownWasPressed()){ + hoodDefault += 0.02; + } + + robot.hood.setPosition(hoodDefault); + + shooter.setTurretPosition(0.3); + + aprilTag.initTelemetry(); + + aprilTag.update(); + shooter.update(); + + TELE.addData("hood", hoodDefault); + + TELE.update(); + + + } + + + waitForStart(); + + if (isStopRequested()) return; + + if (opModeIsActive()){ + + robot.hood.setPosition(hoodDefault); + + transfer.setTransferPower(1); + + transfer.update(); + + + + + Actions.runBlocking( + new ParallelAction( + traj1.build(), + new shooterOn() + ) + ); + + + transfer.setTransferPower(1); + + transfer.update(); + + shooter.setManualPower(1); + + double stamp = getRuntime(); + + + stamp = getRuntime(); + + while (getRuntime()-stamp<4.5) { + + + + shooter.moveTurret(0.3); + + double time = getRuntime()-stamp; + + + if (time < 0.3) { + + + transfer.transferOut(); + transfer.setTransferPower(1); + } else if (time < 1) { + + spindexer.outtake3(); + + + } else if (time < 1.4) { + + + transfer.transferIn(); + } else if (time < 2.6) { + transfer.transferOut(); + + spindexer.outtake2(); + + + + } else if (time < 3.0) { + + + transfer.transferIn(); + } else if (time < 4.0) { + + transfer.transferOut(); + + spindexer.outtake1(); + + } else if (time < 4.4) { + transfer.transferIn(); + } else { + + transfer.transferOut(); + spindexer.outtake3(); + + shooter.setManualPower(1); + + } + + transfer.update(); + + shooter.update(); + + spindexer.update(); + + } + + spindexer.outtake3(); + + robot.intake.setPower(1); + + Actions.runBlocking( + traj2.build() + ); + + + Actions.runBlocking( + traj3.build() + ); + + shooter.setManualPower(1); + + + + + robot.intake.setPower(0); + + spindexer.outtake3(); + + + stamp = getRuntime(); + + shooter.setManualPower(1); + while (getRuntime()-stamp<4.5) { + + + + shooter.moveTurret(0.3); + + double time = getRuntime()-stamp; + + + if (time < 0.3) { + + + transfer.transferOut(); + transfer.setTransferPower(1); + } else if (time < 1) { + + spindexer.outtake3(); + + + } else if (time < 1.4) { + + + transfer.transferIn(); + } else if (time < 2.6) { + transfer.transferOut(); + + spindexer.outtake2(); + + + + } else if (time < 3.0) { + + + transfer.transferIn(); + } else if (time < 4.0) { + + transfer.transferOut(); + + spindexer.outtake1(); + + } else if (time < 4.4) { + transfer.transferIn(); + } else { + + transfer.transferOut(); + spindexer.outtake3(); + + shooter.setManualPower(1); + + } + + transfer.update(); + + shooter.update(); + + spindexer.update(); + + } + + spindexer.outtake3(); + robot.intake.setPower(1); + + Actions.runBlocking( + traj4.build() + ); + + + Actions.runBlocking( + traj5.build() + ); + + shooter.setManualPower(1); + + + + + robot.intake.setPower(0); + + + stamp = getRuntime(); + + shooter.setManualPower(1); + + while (getRuntime()-stamp<4.5) { + + + + shooter.moveTurret(0.3); + + double time = getRuntime()-stamp; + + + if (time < 0.3) { + + + transfer.transferOut(); + transfer.setTransferPower(1); + } else if (time < 1) { + + spindexer.outtake3(); + + + } else if (time < 1.4) { + + + transfer.transferIn(); + } else if (time < 2.6) { + transfer.transferOut(); + + spindexer.outtake2(); + + + + } else if (time < 3.0) { + + + transfer.transferIn(); + } else if (time < 4.0) { + + transfer.transferOut(); + + spindexer.outtake1(); + + } else if (time < 4.4) { + transfer.transferIn(); + } else { + + transfer.transferOut(); + spindexer.outtake3(); + + shooter.setManualPower(1); + + } + + transfer.update(); + + shooter.update(); + + spindexer.update(); + + } + + spindexer.outtake3(); + + Actions.runBlocking( + traj6.build() + ); + + drive.updatePoseEstimate(); + + teleStart = drive.localizer.getPose(); + + TELE.addLine("finished"); + + TELE.update(); + + sleep (2000); + + + } + + } +} diff --git a/TeamCode/src/main/java/org/firstinspires/ftc/teamcode/autonomous/Red.java b/TeamCode/src/main/java/org/firstinspires/ftc/teamcode/autonomous/Red.java new file mode 100644 index 0000000..5da26ae --- /dev/null +++ b/TeamCode/src/main/java/org/firstinspires/ftc/teamcode/autonomous/Red.java @@ -0,0 +1,431 @@ +package org.firstinspires.ftc.teamcode.autonomous; + +import static org.firstinspires.ftc.teamcode.constants.Poses.*; +import static org.firstinspires.ftc.teamcode.constants.ServoPositions.*; + +import androidx.annotation.NonNull; + +import com.acmerobotics.dashboard.FtcDashboard; +import com.acmerobotics.dashboard.config.Config; +import com.acmerobotics.dashboard.telemetry.MultipleTelemetry; +import com.acmerobotics.dashboard.telemetry.TelemetryPacket; +import com.acmerobotics.roadrunner.Action; +import com.acmerobotics.roadrunner.ParallelAction; +import com.acmerobotics.roadrunner.Pose2d; +import com.acmerobotics.roadrunner.SequentialAction; +import com.acmerobotics.roadrunner.TrajectoryActionBuilder; +import com.acmerobotics.roadrunner.Vector2d; +import com.acmerobotics.roadrunner.ftc.Actions; +import com.qualcomm.robotcore.eventloop.opmode.Autonomous; +import com.qualcomm.robotcore.eventloop.opmode.LinearOpMode; + +import org.firstinspires.ftc.teamcode.constants.ServoPositions; +import org.firstinspires.ftc.teamcode.libs.RR.MecanumDrive; +import org.firstinspires.ftc.teamcode.subsystems.AprilTag; +import org.firstinspires.ftc.teamcode.subsystems.Intake; +import org.firstinspires.ftc.teamcode.subsystems.Shooter; +import org.firstinspires.ftc.teamcode.subsystems.Spindexer; +import org.firstinspires.ftc.teamcode.subsystems.Transfer; +import org.firstinspires.ftc.teamcode.utils.Robot; +import static org.firstinspires.ftc.teamcode.constants.ServoPositions.*; + + + +@Config +@Autonomous +public class Red extends LinearOpMode { + + Robot robot; + + MultipleTelemetry TELE; + + MecanumDrive drive; + + AprilTag aprilTag; + + Shooter shooter; + + + + public static double angle = 0.1; + + Spindexer spindexer; + + Transfer transfer; + + + + + + @Override + public void runOpMode() throws InterruptedException { + + + + + robot = new Robot(hardwareMap); + TELE = new MultipleTelemetry( + telemetry, FtcDashboard.getInstance().getTelemetry() + ); + + drive = new MecanumDrive(hardwareMap, new Pose2d( + 0,0,0 + )); + + aprilTag = new AprilTag(robot, TELE); + + shooter = new Shooter(robot, TELE); + + spindexer = new Spindexer(robot, TELE); + + spindexer.outtake3(); + + shooter.setShooterMode("MANUAL"); + + shooter.sethoodPosition(hoodDefault); + + transfer = new Transfer(robot); + + transfer.setTransferPosition(transferServo_out); + + Intake intake = new Intake(robot); + + robot.hood.setPosition(hoodDefault); + + + + + + + + + TrajectoryActionBuilder traj1 = drive.actionBuilder(new Pose2d(0, 0, 0)) + .strafeToLinearHeading(new Vector2d(x1, y1), h1 ); + + + TrajectoryActionBuilder traj2 = drive.actionBuilder(new Pose2d(x1, y1, h1)) + .turnTo(Math.toRadians(135)) + .strafeToLinearHeading(new Vector2d(x2, y2), h2 ); + + + TrajectoryActionBuilder traj3 = drive.actionBuilder(new Pose2d(x2, y2, h2)) + .strafeToLinearHeading(new Vector2d(x1, y1), h1 ); + + TrajectoryActionBuilder traj4 = drive.actionBuilder(new Pose2d(x1, y1, h1)) + + .strafeToLinearHeading(new Vector2d(x2_b, y2_b), h2_b ) + + .strafeToLinearHeading(new Vector2d(x3, y3), h3 ); + + + TrajectoryActionBuilder traj5 = drive.actionBuilder(new Pose2d(x3, y3, h3)) + .strafeToLinearHeading(new Vector2d(x1, y1), h1 ); + + + TrajectoryActionBuilder traj6 = drive.actionBuilder(new Pose2d(x1, y1, h1)) + .strafeToLinearHeading(new Vector2d(x1, y1+30), h1 ); + + while(opModeInInit()) { + + if (gamepad2.dpadUpWasPressed()){ + hoodDefault -= 0.02; + } + + if (gamepad2.dpadDownWasPressed()){ + hoodDefault += 0.02; + } + + robot.hood.setPosition(hoodDefault); + + shooter.setTurretPosition(0.33); + + aprilTag.initTelemetry(); + + aprilTag.update(); + shooter.update(); + + TELE.update(); + } + + + waitForStart(); + + if (isStopRequested()) return; + + if (opModeIsActive()){ + + robot.hood.setPosition(hoodDefault); + + transfer.setTransferPower(1); + + transfer.update(); + + + + + Actions.runBlocking( + new ParallelAction( + traj1.build() + ) + ); + + + transfer.setTransferPower(1); + + transfer.update(); + + shooter.setManualPower(1); + + double stamp = getRuntime(); + + + stamp = getRuntime(); + + while (getRuntime()-stamp<4.5) { + + + + shooter.moveTurret(0.31); + + double time = getRuntime()-stamp; + + + if (time < 0.3) { + + + transfer.transferOut(); + transfer.setTransferPower(1); + } else if (time < 1) { + + spindexer.outtake3(); + + + } else if (time < 1.4) { + + + transfer.transferIn(); + } else if (time < 2.6) { + transfer.transferOut(); + + spindexer.outtake2(); + + + + } else if (time < 3.0) { + + + transfer.transferIn(); + } else if (time < 4.0) { + + transfer.transferOut(); + + spindexer.outtake1(); + + } else if (time < 4.4) { + transfer.transferIn(); + } else { + + transfer.transferOut(); + spindexer.outtake3(); + + shooter.setManualPower(0); + + } + + transfer.update(); + + shooter.update(); + + spindexer.update(); + + } + + spindexer.outtake3(); + + robot.intake.setPower(1); + + Actions.runBlocking( + traj2.build() + ); + + + Actions.runBlocking( + traj3.build() + ); + + shooter.setManualPower(1); + + + + + robot.intake.setPower(0); + + spindexer.outtake3(); + + + stamp = getRuntime(); + + shooter.setManualPower(1); + while (getRuntime()-stamp<4.5) { + + + + shooter.moveTurret(0.31); + + double time = getRuntime()-stamp; + + + if (time < 0.3) { + + + transfer.transferOut(); + transfer.setTransferPower(1); + } else if (time < 1) { + + spindexer.outtake3(); + + + } else if (time < 1.4) { + + + transfer.transferIn(); + } else if (time < 2.6) { + transfer.transferOut(); + + spindexer.outtake2(); + + + + } else if (time < 3.0) { + + + transfer.transferIn(); + } else if (time < 4.0) { + + transfer.transferOut(); + + spindexer.outtake1(); + + } else if (time < 4.4) { + transfer.transferIn(); + } else { + + transfer.transferOut(); + spindexer.outtake3(); + + shooter.setManualPower(0); + + } + + transfer.update(); + + shooter.update(); + + spindexer.update(); + + } + + spindexer.outtake3(); + robot.intake.setPower(1); + + Actions.runBlocking( + traj4.build() + ); + + + Actions.runBlocking( + traj5.build() + ); + + shooter.setManualPower(1); + + + + + robot.intake.setPower(0); + + + stamp = getRuntime(); + + shooter.setManualPower(1); + + while (getRuntime()-stamp<4.5) { + + + + shooter.moveTurret(0.31); + + double time = getRuntime()-stamp; + + + if (time < 0.3) { + + + transfer.transferOut(); + transfer.setTransferPower(1); + } else if (time < 1) { + + spindexer.outtake3(); + + + } else if (time < 1.4) { + + + transfer.transferIn(); + } else if (time < 2.6) { + transfer.transferOut(); + + spindexer.outtake2(); + + + + } else if (time < 3.0) { + + + transfer.transferIn(); + } else if (time < 4.0) { + + transfer.transferOut(); + + spindexer.outtake1(); + + } else if (time < 4.4) { + transfer.transferIn(); + } else { + + transfer.transferOut(); + spindexer.outtake3(); + + shooter.setManualPower(0); + + } + + transfer.update(); + + shooter.update(); + + spindexer.update(); + + } + + spindexer.outtake3(); + + Actions.runBlocking( + traj6.build() + ); + + drive.updatePoseEstimate(); + + teleStart = drive.localizer.getPose(); + + TELE.addLine("finished"); + + TELE.update(); + + sleep (2000); + + + } + + } +} diff --git a/TeamCode/src/main/java/org/firstinspires/ftc/teamcode/autonomous/blank.java b/TeamCode/src/main/java/org/firstinspires/ftc/teamcode/autonomous/blank.java new file mode 100644 index 0000000..2c80fab --- /dev/null +++ b/TeamCode/src/main/java/org/firstinspires/ftc/teamcode/autonomous/blank.java @@ -0,0 +1,4 @@ +package org.firstinspires.ftc.teamcode.autonomous; + +public class blank { +} diff --git a/TeamCode/src/main/java/org/firstinspires/ftc/teamcode/constants/Poses.java b/TeamCode/src/main/java/org/firstinspires/ftc/teamcode/constants/Poses.java new file mode 100644 index 0000000..6cc3514 --- /dev/null +++ b/TeamCode/src/main/java/org/firstinspires/ftc/teamcode/constants/Poses.java @@ -0,0 +1,29 @@ +package org.firstinspires.ftc.teamcode.constants; + + +import com.acmerobotics.dashboard.config.Config; +import com.acmerobotics.roadrunner.Pose2d; + +@Config +public class Poses { + + public static double goalHeight = 42; //in inches + + public static double turretHeight = 12; + + public static double relativeGoalHeight = goalHeight - turretHeight; + + public static double x1 = 50, y1 = 0, h1 = 0; + + public static double x2 = 31, y2 = 32, h2 = Math.toRadians(135); + + public static double x2_b = 58, y2_b = 42, h2_b = Math.toRadians(135); + + + public static double x3 = 34, y3 = 58, h3 = Math.toRadians(135); + + public static Pose2d teleStart = new Pose2d(x1,-10,0); + + + +} diff --git a/TeamCode/src/main/java/org/firstinspires/ftc/teamcode/constants/ServoPositions.java b/TeamCode/src/main/java/org/firstinspires/ftc/teamcode/constants/ServoPositions.java new file mode 100644 index 0000000..beb7514 --- /dev/null +++ b/TeamCode/src/main/java/org/firstinspires/ftc/teamcode/constants/ServoPositions.java @@ -0,0 +1,23 @@ +package org.firstinspires.ftc.teamcode.constants; + + +import com.acmerobotics.dashboard.config.Config; + +@Config +public class ServoPositions { + + public static double spindexer_intakePos = 0.665; + + public static double spindexer_outtakeBall3 = 0.845; + + public static double spindexer_outtakeBall2 = 0.48; + public static double spindexer_outtakeBall1 = 0.1; + + public static double transferServo_out = 0.13; + + public static double transferServo_in = 0.4; + + public static double hoodDefault = 0.35; + + +} diff --git a/TeamCode/src/main/java/org/firstinspires/ftc/teamcode/constants/blank.java b/TeamCode/src/main/java/org/firstinspires/ftc/teamcode/constants/blank.java new file mode 100644 index 0000000..53e7fcb --- /dev/null +++ b/TeamCode/src/main/java/org/firstinspires/ftc/teamcode/constants/blank.java @@ -0,0 +1,4 @@ +package org.firstinspires.ftc.teamcode.constants; + +public class blank { +} diff --git a/TeamCode/src/main/java/org/firstinspires/ftc/teamcode/disabled/blank.java b/TeamCode/src/main/java/org/firstinspires/ftc/teamcode/disabled/blank.java new file mode 100644 index 0000000..9258773 --- /dev/null +++ b/TeamCode/src/main/java/org/firstinspires/ftc/teamcode/disabled/blank.java @@ -0,0 +1,4 @@ +package org.firstinspires.ftc.teamcode.disabled; + +public class blank { +} diff --git a/TeamCode/src/main/java/org/firstinspires/ftc/teamcode/libs/RR/Drawing.java b/TeamCode/src/main/java/org/firstinspires/ftc/teamcode/libs/RR/Drawing.java new file mode 100644 index 0000000..764c4ee --- /dev/null +++ b/TeamCode/src/main/java/org/firstinspires/ftc/teamcode/libs/RR/Drawing.java @@ -0,0 +1,22 @@ +package org.firstinspires.ftc.teamcode.libs.RR; + +import com.acmerobotics.dashboard.canvas.Canvas; +import com.acmerobotics.roadrunner.Pose2d; +import com.acmerobotics.roadrunner.Vector2d; + +public final class Drawing { + private Drawing() {} + + + public static void drawRobot(Canvas c, Pose2d t) { + final double ROBOT_RADIUS = 9; + + c.setStrokeWidth(1); + c.strokeCircle(t.position.x, t.position.y, ROBOT_RADIUS); + + Vector2d halfv = t.heading.vec().times(0.5 * ROBOT_RADIUS); + Vector2d p1 = t.position.plus(halfv); + Vector2d p2 = p1.plus(halfv); + c.strokeLine(p1.x, p1.y, p2.x, p2.y); + } +} diff --git a/TeamCode/src/main/java/org/firstinspires/ftc/teamcode/libs/RR/Localizer.java b/TeamCode/src/main/java/org/firstinspires/ftc/teamcode/libs/RR/Localizer.java new file mode 100644 index 0000000..970c400 --- /dev/null +++ b/TeamCode/src/main/java/org/firstinspires/ftc/teamcode/libs/RR/Localizer.java @@ -0,0 +1,25 @@ +package org.firstinspires.ftc.teamcode.libs.RR; + +import com.acmerobotics.roadrunner.Pose2d; +import com.acmerobotics.roadrunner.PoseVelocity2d; + +/** + * Interface for localization methods. + */ +public interface Localizer { + void setPose(Pose2d pose); + + /** + * Returns the current pose estimate. + * NOTE: Does not update the pose estimate; + * you must call update() to update the pose estimate. + * @return the Localizer's current pose + */ + Pose2d getPose(); + + /** + * Updates the Localizer's pose estimate. + * @return the Localizer's current velocity estimate + */ + PoseVelocity2d update(); +} diff --git a/TeamCode/src/main/java/org/firstinspires/ftc/teamcode/libs/RR/MecanumDrive.java b/TeamCode/src/main/java/org/firstinspires/ftc/teamcode/libs/RR/MecanumDrive.java new file mode 100644 index 0000000..45ad2e2 --- /dev/null +++ b/TeamCode/src/main/java/org/firstinspires/ftc/teamcode/libs/RR/MecanumDrive.java @@ -0,0 +1,500 @@ +package org.firstinspires.ftc.teamcode.libs.RR; + +import androidx.annotation.NonNull; + +import com.acmerobotics.dashboard.canvas.Canvas; +import com.acmerobotics.dashboard.config.Config; +import com.acmerobotics.dashboard.telemetry.TelemetryPacket; +import com.acmerobotics.roadrunner.*; +import com.acmerobotics.roadrunner.AngularVelConstraint; +import com.acmerobotics.roadrunner.DualNum; +import com.acmerobotics.roadrunner.HolonomicController; +import com.acmerobotics.roadrunner.MecanumKinematics; +import com.acmerobotics.roadrunner.MinVelConstraint; +import com.acmerobotics.roadrunner.MotorFeedforward; +import com.acmerobotics.roadrunner.Pose2d; +import com.acmerobotics.roadrunner.Pose2dDual; +import com.acmerobotics.roadrunner.ProfileAccelConstraint; +import com.acmerobotics.roadrunner.Time; +import com.acmerobotics.roadrunner.TimeTrajectory; +import com.acmerobotics.roadrunner.TimeTurn; +import com.acmerobotics.roadrunner.TrajectoryActionBuilder; +import com.acmerobotics.roadrunner.TurnConstraints; +import com.acmerobotics.roadrunner.VelConstraint; +import com.acmerobotics.roadrunner.ftc.DownsampledWriter; +import com.acmerobotics.roadrunner.ftc.Encoder; +import com.acmerobotics.roadrunner.ftc.FlightRecorder; +import com.acmerobotics.roadrunner.ftc.LazyHardwareMapImu; +import com.acmerobotics.roadrunner.ftc.LazyImu; +import com.acmerobotics.roadrunner.ftc.LynxFirmware; +import com.acmerobotics.roadrunner.ftc.OverflowEncoder; +import com.acmerobotics.roadrunner.ftc.PositionVelocityPair; +import com.acmerobotics.roadrunner.ftc.RawEncoder; +import com.qualcomm.hardware.lynx.LynxModule; +import com.qualcomm.hardware.rev.RevHubOrientationOnRobot; +import com.qualcomm.robotcore.hardware.DcMotor; +import com.qualcomm.robotcore.hardware.DcMotorEx; +import com.qualcomm.robotcore.hardware.DcMotorSimple; +import com.qualcomm.robotcore.hardware.HardwareMap; +import com.qualcomm.robotcore.hardware.IMU; +import com.qualcomm.robotcore.hardware.VoltageSensor; + +import org.firstinspires.ftc.robotcore.external.navigation.AngleUnit; +import org.firstinspires.ftc.robotcore.external.navigation.YawPitchRollAngles; +import org.firstinspires.ftc.teamcode.libs.RR.messages.DriveCommandMessage; +import org.firstinspires.ftc.teamcode.libs.RR.messages.MecanumCommandMessage; +import org.firstinspires.ftc.teamcode.libs.RR.messages.MecanumLocalizerInputsMessage; +import org.firstinspires.ftc.teamcode.libs.RR.messages.PoseMessage; + +import java.lang.Math; +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; + +@Config +public final class MecanumDrive { + public static class Params { + // IMU orientation + // TODO: fill in these values based on + // see https://ftc-docs.firstinspires.org/en/latest/programming_resources/imu/imu.html?highlight=imu#physical-hub-mounting + public RevHubOrientationOnRobot.LogoFacingDirection logoFacingDirection = + RevHubOrientationOnRobot.LogoFacingDirection.RIGHT; + public RevHubOrientationOnRobot.UsbFacingDirection usbFacingDirection = + RevHubOrientationOnRobot.UsbFacingDirection.BACKWARD; + + // drive model parameters + public double inPerTick = 0.001978956; + public double lateralInPerTick = 0.0013863732202094405; + public double trackWidthTicks = 6488.883015684446; + + // feedforward parameters (in tick units) + public double kS = 1.2147826978829488; + public double kV = 0.00032; + public double kA = 0.000046; + + // path profile parameters (in inches) + public double maxWheelVel = 120; + public double minProfileAccel = -30; + public double maxProfileAccel = 120; + + // turn profile parameters (in radians) + public double maxAngVel = 2* Math.PI; // shared with path + public double maxAngAccel = 2* Math.PI; + + // path controller gains + public double axialGain = 4; + public double lateralGain = 4; + public double headingGain = 4; // shared with turn + + public double axialVelGain = 0.0; + public double lateralVelGain = 0.0; + public double headingVelGain = 0.0; // shared with turn + } + + public static Params PARAMS = new Params(); + + public final MecanumKinematics kinematics = new MecanumKinematics( + PARAMS.inPerTick * PARAMS.trackWidthTicks, PARAMS.inPerTick / PARAMS.lateralInPerTick); + + public final TurnConstraints defaultTurnConstraints = new TurnConstraints( + PARAMS.maxAngVel, -PARAMS.maxAngAccel, PARAMS.maxAngAccel); + public final VelConstraint defaultVelConstraint = + new MinVelConstraint(Arrays.asList( + kinematics.new WheelVelConstraint(PARAMS.maxWheelVel), + new AngularVelConstraint(PARAMS.maxAngVel) + )); + public final AccelConstraint defaultAccelConstraint = + new ProfileAccelConstraint(PARAMS.minProfileAccel, PARAMS.maxProfileAccel); + + public final DcMotorEx leftFront, leftBack, rightBack, rightFront; + + public final VoltageSensor voltageSensor; + + public final LazyImu lazyImu; + + public final Localizer localizer; + private final LinkedList poseHistory = new LinkedList<>(); + + private final DownsampledWriter estimatedPoseWriter = new DownsampledWriter("ESTIMATED_POSE", 50_000_000); + private final DownsampledWriter targetPoseWriter = new DownsampledWriter("TARGET_POSE", 50_000_000); + private final DownsampledWriter driveCommandWriter = new DownsampledWriter("DRIVE_COMMAND", 50_000_000); + private final DownsampledWriter mecanumCommandWriter = new DownsampledWriter("MECANUM_COMMAND", 50_000_000); + + public class DriveLocalizer implements Localizer { + public final Encoder leftFront, leftBack, rightBack, rightFront; + public final IMU imu; + + private int lastLeftFrontPos, lastLeftBackPos, lastRightBackPos, lastRightFrontPos; + private Rotation2d lastHeading; + private boolean initialized; + private Pose2d pose; + + public DriveLocalizer(Pose2d pose) { + leftFront = new OverflowEncoder(new RawEncoder(MecanumDrive.this.leftFront)); + leftBack = new OverflowEncoder(new RawEncoder(MecanumDrive.this.leftBack)); + rightBack = new OverflowEncoder(new RawEncoder(MecanumDrive.this.rightBack)); + rightFront = new OverflowEncoder(new RawEncoder(MecanumDrive.this.rightFront)); + + imu = lazyImu.get(); + + // TODO: reverse encoders if needed + // leftFront.setDirection(DcMotorSimple.Direction.REVERSE); + + this.pose = pose; + } + + @Override + public void setPose(Pose2d pose) { + this.pose = pose; + } + + @Override + public Pose2d getPose() { + return pose; + } + + @Override + public PoseVelocity2d update() { + PositionVelocityPair leftFrontPosVel = leftFront.getPositionAndVelocity(); + PositionVelocityPair leftBackPosVel = leftBack.getPositionAndVelocity(); + PositionVelocityPair rightBackPosVel = rightBack.getPositionAndVelocity(); + PositionVelocityPair rightFrontPosVel = rightFront.getPositionAndVelocity(); + + YawPitchRollAngles angles = imu.getRobotYawPitchRollAngles(); + + FlightRecorder.write("MECANUM_LOCALIZER_INPUTS", new MecanumLocalizerInputsMessage( + leftFrontPosVel, leftBackPosVel, rightBackPosVel, rightFrontPosVel, angles)); + + Rotation2d heading = Rotation2d.exp(angles.getYaw(AngleUnit.RADIANS)); + + if (!initialized) { + initialized = true; + + lastLeftFrontPos = leftFrontPosVel.position; + lastLeftBackPos = leftBackPosVel.position; + lastRightBackPos = rightBackPosVel.position; + lastRightFrontPos = rightFrontPosVel.position; + + lastHeading = heading; + + return new PoseVelocity2d(new Vector2d(0.0, 0.0), 0.0); + } + + double headingDelta = heading.minus(lastHeading); + Twist2dDual