diff --git a/docs/section-5/pull-requests.md b/docs/section-5/pull-requests.md index 1ced945..72ef15f 100644 --- a/docs/section-5/pull-requests.md +++ b/docs/section-5/pull-requests.md @@ -4,7 +4,7 @@ Feature branches should go through two code reviews: 1. The first one where there is no new implementation. All code here is either structural code (classes and methods setup but not implemented), or code that we have already written in the past (such as drivetrain code). This is to catch structural problems early on and have the reviewer familiarize themself with the code so it will be easier to do the final review. When unit tests are necessary, they should also be written in this phase. 2. The second one should be the final code review. This is looking at the entire finished feature and making sure that it is written correctly. -Each pull request should be reviewed by at least one student, and it is preferable, although not required, to have that student do both reviews. +Each pull request should be reviewed by at least one student, and it is preferable, although not required, to have that student do both reviews. Also make sure to consult with Dean or any other programming mentor before having a PR fully approved. The more people reviewing, the better. ## Unit Testing What code needs unit tests is explained in [section 6](/section-6/why-tests/), but the programming leads/mentors may request that unit tests be written for a branch to be merged. diff --git a/docs/section-7/PathPlanner.png b/docs/section-7/PathPlanner.png new file mode 100644 index 0000000..834f697 Binary files /dev/null and b/docs/section-7/PathPlanner.png differ diff --git a/docs/section-7/PathPlanner_Autos.png b/docs/section-7/PathPlanner_Autos.png new file mode 100644 index 0000000..284d536 Binary files /dev/null and b/docs/section-7/PathPlanner_Autos.png differ diff --git a/docs/section-7/PathPlanner_Paths.png b/docs/section-7/PathPlanner_Paths.png new file mode 100644 index 0000000..2353982 Binary files /dev/null and b/docs/section-7/PathPlanner_Paths.png differ diff --git a/docs/section-7/pathweaver.md b/docs/section-7/pathweaver.md index 3e25c05..d95ebe2 100644 --- a/docs/section-7/pathweaver.md +++ b/docs/section-7/pathweaver.md @@ -1,9 +1,159 @@ +In this section, you will learn how to write Autonomous code. As mentioned before, the Autonomous code is for the Autonomous period during the game. While our bots are in the Autonomous period, It can score, leave the safezone, or even ruin other autos depending on how ambitous your autonomous will be. It'll be fun. + +Quick note, While you are writing your Autonomous Code and plotting your paths, consider your constraints and strategies. Make sure you are utilizing the robot's potential to the fullest, making as many autonomous paths to give our alliance partners more strategies to work with. Talk with your drive team to see what paths they would like to use during competition. In general, make sure to have a strategic mindset whenever creating autons. + +Now let's write some autonomous code! + +## PathPlanner Tool +Our robots use the [`PathPlanner`](https://pathplanner.dev/home.html) tool for our autonomous as it is an easy and efficient way to set up pathways + +So how exactly do we set this up and get the paths running? + +## Setup in RobotContainer +Firstoff, we want to settup and import PathPlanner into RobotContainer. We will generally use this template to help us configure the PathPlanner tool. Always reference to the [`PathPlanner Docs`](https://pathplanner.dev/home.html) whenever you are configuring the autonomous. + +Here when setting up the auto, we want to get constants such as robot's current positions and plug it into the methods, that way PathPlanner knows where our robot is +``` Java +public class DriveSubsystem extends SubsystemBase { + public DriveSubsystem() { + // All other subsystem initialization + // ... + + // Load the RobotConfig from the GUI settings. You should probably + // store this in your Constants file + RobotConfig config; + try{ + config = RobotConfig.fromGUISettings(); + } catch (Exception e) { + // Handle exception as needed + e.printStackTrace(); + } + + // Configure AutoBuilder last + AutoBuilder.configure( + this::getPose, // Robot pose supplier + this::resetPose, // Method to reset odometry (will be called if your auto has a starting pose) + this::getRobotRelativeSpeeds, // ChassisSpeeds supplier. MUST BE ROBOT RELATIVE + (speeds, feedforwards) -> driveRobotRelative(speeds), // Method that will drive the robot given ROBOT RELATIVE ChassisSpeeds. Also optionally outputs individual module feedforwards + new PPHolonomicDriveController( // PPHolonomicController is the built in path following controller for holonomic drive trains + new PIDConstants(5.0, 0.0, 0.0), // Translation PID constants + new PIDConstants(5.0, 0.0, 0.0) // Rotation PID constants + ), + config, // The robot configuration + () -> { + // Boolean supplier that controls when the path will be mirrored for the red alliance + // This will flip the path being followed to the red side of the field. + // THE ORIGIN WILL REMAIN ON THE BLUE SIDE + + var alliance = DriverStation.getAlliance(); + if (alliance.isPresent()) { + return alliance.get() == DriverStation.Alliance.Red; + } + return false; + }, + this // Reference to this subsystem to set requirements + ); + } +} +``` + +## Creating Named Commands +Now that we have configured our autonomous, we need to create named commands to store the methods we will use in the PathPlanner tool(Example: Shooter Commands) + +We always want to name our commands, that way we know which one to use when creating our autonomous + +Then we want to run one actual command we created such as shooter so we would put the command name in there, and list the subsystem name as one of the parameters that way it knows what subsytem to use + +``` Java +public class RobotContainer() { + public RobotContainer() { + // Subsystem initialization + swerve = new Swerve(); + exampleSubsystem = new ExampleSubsystem(); + + // Register Named Commands + NamedCommands.registerCommand("autoBalance", swerve.autoBalanceCommand()); + NamedCommands.registerCommand("exampleCommand", exampleSubsystem.exampleCommand()); + NamedCommands.registerCommand("someOtherCommand", new SomeOtherCommand()); + //Example of a command we used on our bot + NamedCommands.registerCommand("PassToOuttake", new PassToOuttake(intakeShooter)); + + // Do all other initialization + configureButtonBindings(); + + // ... + } +} +``` +## Registering Autos On SmartDashboard +During competitions, strategies will change throughout matches, so you are going to want to change your autos depending on that strategy drive team comes up with + +The question is how do we select auto right before a match? + +It's pretty simple, all you have to do is register your autos onto SmartDashboard: + +``` Java + private List autoCommands = new ArrayList(); + private SendableChooser autoSelector = new SendableChooser(); + + private boolean hasSetupAutos = false; + private final String[] autoNames = new String[] { + /* These are assumed to be equal to the AUTO ames in pathplanner */ + + "1 Piece Shoot Auto", "2 Piece Shoot Auto", "3 Piece Shoot Auto", + + "Raise Arm", "Swing Arm", "Still Arm", + + "Auto Ruiner", "Safehouse Move", "No Moving", + }; + DigitalInput[] autoSelectors = new DigitalInput[Math.min(autoNames.length, 10)]; + + public RobotContainer() { + registerAutoCommands(); + SmartDashboard.putData(autoSelector); + SmartDashboard.setPersistent("SendableChooser[0]"); + } + +``` +What is happening here is we are putting our auto names in this array and creating a SmartDashboard selector to select our autos during a competition + +## Running Autos In Code +Now that we have all of our Autos set up, we need to tell the robot to run and build the autonomous command + +``` Java +public class RobotContainer { + private final SendableChooser autoChooser; + + public RobotContainer() { + // Another option that allows you to specify the default auto by its name + // autoChooser = AutoBuilder.buildAutoChooser("My Default Auto"); + + public Command getAutonomousCommand() { + return autoSelectors.getSelected(); + } +} +``` +What this code does is that it gets the autonomous we chose from SmartDashboard and plugs it into the getAutonomousCommand() + +## creating autos! +Now that we have settup the neccesary code for auto, you can start creating autos and setting up paths. One of the best parts of the autonomous creation process. + +Open up your PathPlanner app, and open your robot project. Once that is finished, your going to create a new path, and set the robot's starting postion on the field(the green box). You can add paths by simply clicking on add a waypoint and moving it. Once you have a path created, exit out of your path creation and head to the autos section. The autos section is where you can combine paths and commands(like shoot) to make a fully functioning autonomous. It's pretty similar to creating a path. When creating an auto, you are going to add your different paths and registered commands from robot container to your auto. Once you have an auto created, it should automatically register on your source branch, and you can commit it! + +![PathPlanner](PathPlanner).png) + +![PathPlanner Paths](PathPlanner_Paths.png) + +![PathPlanner Autos](PathPlanner_Autos.png) + +That's about it, have fun creating your autonomous code! + + +## PathWeaver Section(Old Stuff) One advantage of a characterized drivetrain is that it more effectively drives the robot to a precise location. This makes following autonomous paths a more viable option. All we need to do is tell the robot a specific path to follow and the robot will drive the path pretty accurately. But how do we specify these paths? We use the `Trajectory` class along with WPILib's Pathweaver tool. For a more detailed description of how to use this class, check out WPIlib's [documentation](https://docs.wpilib.org/en/stable/docs/software/examples-tutorials/trajectory-tutorial/index.html). -Let's write some autonomous code! - ## Trajectories The [`Trajectory`](https://first.wpi.edu/FRC/roborio/release/docs/java/edu/wpi/first/wpilibj/trajectory/Trajectory.html) class creates a smooth path through a list of states. Each state contains information such as the position on the field, time elapsed, velocity, acceleration, pose, and the curvature of the path. Once you have built your paths using Pathweaver, you can use the [`fromPathweaverJson()`](https://first.wpi.edu/FRC/roborio/release/docs/java/edu/wpi/first/wpilibj/trajectory/TrajectoryUtil.html#fromPathweaverJson(java.nio.file.Path)) method from [`TrajectoryUtil`](https://first.wpi.edu/FRC/roborio/release/docs/java/edu/wpi/first/wpilibj/trajectory/TrajectoryUtil.html) to create a Trajectory from the built path. This will be the primary way in which we create our `Trajectory` objects.