diff --git a/src/main/java/frc/robot/commands/drive/JoystickDrive.java b/src/main/java/frc/robot/commands/drive/JoystickDrive.java index f2ab04e..8f54e95 100644 --- a/src/main/java/frc/robot/commands/drive/JoystickDrive.java +++ b/src/main/java/frc/robot/commands/drive/JoystickDrive.java @@ -47,6 +47,7 @@ public JoystickDrive( super.addRequirements(driveSubsystem); resetSensitivity(); + SwerveDrive.swerveHeadingController.setHeadingRequest(new ChassisHeadingController.NullRequest()); } @Override diff --git a/src/main/java/frc/robot/utils/AIRobotInSimulation.java b/src/main/java/frc/robot/utils/AIRobotInSimulation.java index b0a77a9..64085b0 100644 --- a/src/main/java/frc/robot/utils/AIRobotInSimulation.java +++ b/src/main/java/frc/robot/utils/AIRobotInSimulation.java @@ -1,6 +1,6 @@ package frc.robot.utils; -import static edu.wpi.first.units.Units.Kilograms; +import static edu.wpi.first.units.Units.*; import com.pathplanner.lib.commands.FollowPathCommand; import com.pathplanner.lib.config.ModuleConfig; @@ -18,10 +18,7 @@ import edu.wpi.first.wpilibj.XboxController; import edu.wpi.first.wpilibj.smartdashboard.SendableChooser; import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard; -import edu.wpi.first.wpilibj2.command.Command; -import edu.wpi.first.wpilibj2.command.Commands; -import edu.wpi.first.wpilibj2.command.SequentialCommandGroup; -import edu.wpi.first.wpilibj2.command.Subsystem; +import edu.wpi.first.wpilibj2.command.*; import edu.wpi.first.wpilibj2.command.button.RobotModeTriggers; import java.util.Arrays; import java.util.function.Supplier; @@ -32,8 +29,23 @@ import org.ironmaple.simulation.seasonspecific.crescendo2024.NoteOnFly; import org.ironmaple.utils.FieldMirroringUtils; -public class AIRobotInSimulation implements Subsystem { - /* if an opponent robot is not requested to be on field, it queens outside the field for performance */ +/** + * + * + *
This class models an AI-controlled robot used during simulation for driver practice and skill development. + * + *
The AI robots are capable of performing various tasks to enhance training scenarios, including: + * + *
The opponent robots will not appear on the field immediately. They are initially placed at + * the {@link #ROBOT_QUEENING_POSITIONS}. + * + *
Instead of being active right away, a sendable chooser is sent to the dashboard, allowing the user to select
+ * the mode of these robots.
+ */
public static void startOpponentRobotSimulations() {
try {
- instances[0] = new AIRobotInSimulation(
+ // Creates an instance of the first AI robot
+ instances[0] = new AIRobotInSimulation(0);
+ // Builds the behavior chooser for the first AI robot
+ instances[0].buildBehaviorChooser(
PathPlannerPath.fromPathFile("opponent robot cycle path 0"),
Commands.none(),
PathPlannerPath.fromPathFile("opponent robot cycle path 0 backwards"),
Commands.none(),
- ROBOT_QUEENING_POSITIONS[0],
- 1);
- instances[1] = new AIRobotInSimulation(
+ new XboxController(2));
+
+ // Same of the following:
+
+ instances[1] = new AIRobotInSimulation(1);
+ instances[1].buildBehaviorChooser(
PathPlannerPath.fromPathFile("opponent robot cycle path 1"),
- shootAtSpeaker(1),
+ instances[1].shootAtSpeaker(),
PathPlannerPath.fromPathFile("opponent robot cycle path 1 backwards"),
Commands.none(),
- ROBOT_QUEENING_POSITIONS[1],
- 2);
- instances[2] = new AIRobotInSimulation(
+ new XboxController(3));
+
+ instances[2] = new AIRobotInSimulation(2);
+ instances[2].buildBehaviorChooser(
PathPlannerPath.fromPathFile("opponent robot cycle path 2"),
- shootAtSpeaker(2),
+ instances[2].shootAtSpeaker(),
PathPlannerPath.fromPathFile("opponent robot cycle path 2 backwards"),
Commands.none(),
- ROBOT_QUEENING_POSITIONS[2],
- 3);
- instances[3] = new AIRobotInSimulation(
+ new XboxController(4));
+
+ instances[3] = new AIRobotInSimulation(3);
+ instances[3].buildBehaviorChooser(
PathPlannerPath.fromPathFile("opponent robot cycle path 3"),
- feedShotLow(),
+ instances[3].feedShotLow(),
PathPlannerPath.fromPathFile("opponent robot cycle path 3 backwards"),
Commands.none(),
- ROBOT_QUEENING_POSITIONS[3],
- 4);
- instances[4] = new AIRobotInSimulation(
+ new XboxController(5));
+
+ instances[4] = new AIRobotInSimulation(4);
+ instances[4].buildBehaviorChooser(
PathPlannerPath.fromPathFile("opponent robot cycle path 4"),
- feedShotHigh(),
+ instances[4].feedShotHigh(),
PathPlannerPath.fromPathFile("opponent robot cycle path 4 backwards"),
Commands.none(),
- ROBOT_QUEENING_POSITIONS[4],
- 5);
+ new XboxController(6));
} catch (Exception e) {
DriverStation.reportError("failed to load opponent robot simulation path, error:" + e.getMessage(), false);
}
}
- private static Command shootAtSpeaker(int index) {
- return Commands.runOnce(() -> SimulatedArena.getInstance()
- .addGamePieceProjectile(new NoteOnFly(
- instances[index]
- .driveSimulation
- .getActualPoseInSimulationWorld()
- .getTranslation(),
- new Translation2d(0.3, 0),
- instances[index].driveSimulation.getActualSpeedsFieldRelative(),
- instances[index]
- .driveSimulation
- .getActualPoseInSimulationWorld()
- .getRotation(),
- 0.5,
- 10,
- Math.toRadians(60))
- .asSpeakerShotNote(() -> {})));
- }
+ private final SimplifiedSwerveDriveSimulation driveSimulation;
+ private final Pose2d queeningPose;
+ private final int id;
- private static Command feedShotLow() {
- final int index = 3;
- return Commands.runOnce(() -> SimulatedArena.getInstance()
- .addGamePieceProjectile(new NoteOnFly(
- instances[index]
- .driveSimulation
- .getActualPoseInSimulationWorld()
- .getTranslation(),
- new Translation2d(0.3, 0),
- instances[index].driveSimulation.getActualSpeedsFieldRelative(),
- instances[index]
- .driveSimulation
- .getActualPoseInSimulationWorld()
- .getRotation(),
- 0.5,
- 10,
- Math.toRadians(20))
- .enableBecomeNoteOnFieldAfterTouchGround()));
- }
+ public AIRobotInSimulation(int id) {
+ this.id = id;
+ this.queeningPose = ROBOT_QUEENING_POSITIONS[id];
+ this.driveSimulation =
+ new SimplifiedSwerveDriveSimulation(new SwerveDriveSimulation(DRIVETRAIN_CONFIG, queeningPose));
- private static Command feedShotHigh() {
- final int index = 4;
- return Commands.runOnce(() -> SimulatedArena.getInstance()
- .addGamePieceProjectile(new NoteOnFly(
- instances[index]
- .driveSimulation
- .getActualPoseInSimulationWorld()
- .getTranslation(),
- new Translation2d(0.3, 0),
- instances[index].driveSimulation.getActualSpeedsFieldRelative(),
- instances[index]
- .driveSimulation
- .getActualPoseInSimulationWorld()
- .getRotation(),
- 0.5,
- 10,
- Math.toRadians(55))
- .enableBecomeNoteOnFieldAfterTouchGround()));
+ SimulatedArena.getInstance().addDriveTrainSimulation(driveSimulation.getDriveTrainSimulation());
}
- private final SimplifiedSwerveDriveSimulation driveSimulation;
- private final int id;
-
- public AIRobotInSimulation(
+ /**
+ * Builds the behavior chooser for this opponent robot and sends it to the dashboard. This allows the user to select
+ * the robot's behavior mode during simulation.
+ */
+ public void buildBehaviorChooser(
PathPlannerPath segment0,
Command toRunAtEndOfSegment0,
PathPlannerPath segment1,
Command toRunAtEndOfSegment1,
- Pose2d queeningPose,
- int id) {
- this.id = id;
- this.driveSimulation =
- new SimplifiedSwerveDriveSimulation(new SwerveDriveSimulation(AI_ROBOT_CONFIG, queeningPose));
+ XboxController joystick) {
SendableChooser