Skip to content

2025 stage 3 edits #90

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added Assets/akit.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Assets/bb.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Assets/servo.webp
Binary file not shown.
Binary file added Assets/x44.webp
Binary file not shown.
106 changes: 65 additions & 41 deletions Docs/2_Architecture/2.2_ElectronicsCrashCourse.md

Large diffs are not rendered by default.

47 changes: 23 additions & 24 deletions Docs/2_Architecture/2.3_CommandBased.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,47 +4,46 @@

Command based programming revolves around three concepts: **Subsystems**, **Commands**, and **Triggers**.

A Subsystem is a set of hardware that forms one system on our robot, like the drivetrain, elevator, arm, or intake.
Each subsystem contains some associated hardware (motors, pistons, sensors, etc.) They are the "nouns" of our robot, what it is.
Each Subsystem is generally made to contain a broad set of hardware that will always operate as a unit.
### Subsystems
A Subsystem represents a system on our robot, like the drivetrain, elevator, arm, or intake, that will always operate as a unit.
Each subsystem contains some associated hardware (motors, pistons, sensors, etc).
They are the "nouns" of our robot, or things that it is.

### Commands
Commands are the "verbs" of the robot, or what our robot does.
Each Subsystem can be used by one Command at the same time, but Commands may use many Subsystems.
Commands can be composed together, so the `LineUp`, `Extend`, and `Outake` Commands might be put together to make a `Score` Command.
Commands can be composed together, so the `LineUp`, `Extend`, and `Outtake` Commands might be put together to make a `Score` Command.
Because each Subsystem can only be used by one Command at once, we are safe from multiple pieces of code trying to command the same motor to different speeds, for example.

Subsystems are ways to organize resources that can be used by one Command at a time.

Some hardware might not be stored in a Subsystem if multiple things can/should use it at the same time safely.
For example, a vision setup can be read from by many things, and might not need to be locked by Commands.
Therefore, it might not be stored in a Subsystem.

On the other hand, a roller that is driven by a motor can only go at one speed at a time.
Therefore, we would wrap it in a Subsystem so that only one Command can use it at once.

### Triggers
A Trigger is something which can start a Command.
The classic form of this is a button on the driver's controller.
Another common type is one which checks for when the robot enables.
One non-obvious Trigger we used in 2024 was one which checked when we had detected a game piece in the robot, which we used to flash our LEDs and vibrate the driver controller.
Triggers can be made of any function that returns a boolean which makes them very powerful.
Another common type is one which checks if the robot is enabled.
One non-obvious Trigger we used in 2024 was one which checked when we had detected a game piece in the robot, which then triggered the Commands to flash our LEDs and vibrate the driver controller.
Triggers can be made of any function that returns a boolean, which makes them very powerful, and can be composed together with boolean operators.
Triggers can also be bound to a certain activation event.
For example, we might want something to happen while a condition is true (`whileTrue()`), when a condition changes from false to true (`onTrue()`), or is true for some amount of time (`debounce()`).

Some large Commands are better represented by several Commands and some Triggers!

# update with superstructure stuff later
Subsystems, commands, and triggers are the building blocks of the robot's overall "superstructure".
This will be covered in more detail in the [Superstructure article.](2.10_Superstructure.md)

### Resources

- [WPILib intro to functional programming](https://docs.wpilib.org/en/stable/docs/software/basic-programming/functions-as-data.html).
Read through this article on lambda expressions and functional programming if you haven't already.
- [WPILib docs](https://docs.wpilib.org/en/stable/docs/software/commandbased/index.html).
Read through these docs until you finish "Organizing Command-Based Robot Projects"
- Read through [this article](https://docs.wpilib.org/en/stable/docs/software/basic-programming/functions-as-data.html) on lambda expressions and functional programming if you haven't already.
- Read through [these docs](https://docs.wpilib.org/en/stable/docs/software/commandbased/index.html) until you finish "Organizing Command-Based Robot Projects"
OR watch [this video](https://drive.google.com/file/d/1ykFDfXVYk27aHlXYKTAqtj1U2T80Szdj/view?usp=drive_link).
Presentation notes for the video are [here](CommandBasedPresentationNotes.md).
If you watch the video, it is recommended to also read the [Subsystems](https://docs.wpilib.org/en/stable/docs/software/commandbased/subsystems.html), [Binding Commands to Triggers](https://docs.wpilib.org/en/stable/docs/software/commandbased/binding-commands-to-triggers.html), and [Organizing Command-Based Robot Projects](https://docs.wpilib.org/en/stable/docs/software/commandbased/organizing-command-based.html#) for addition details on using Command-Based.

The important segment of all of this to remember is:
> Commands represent actions the robot can take. Commands run when scheduled, until they are interrupted or their end condition is met. Commands are very recursively composable: commands can be composed to accomplish more-complicated tasks. See Commands for more info.
>
> Subsystems represent independently-controlled collections of robot hardware (such as motor controllers, sensors, pneumatic actuators, etc.) that operate together. Subsystems back the resource-management system of command-based: only one command can use a given subsystem at the same time. Subsystems allow users to “hide” the internal complexity of their actual hardware from the rest of their code - this both simplifies the rest of the robot code, and allows changes to the internal details of a subsystem’s hardware without also changing the rest of the robot code.
Presentation notes for the video are [here](2.4_CommandBasedPresentationNotes.md).

- If you watch the video, it is recommended to also read the [Subsystems](https://docs.wpilib.org/en/stable/docs/software/commandbased/subsystems.html), [Binding Commands to Triggers](https://docs.wpilib.org/en/stable/docs/software/commandbased/binding-commands-to-triggers.html), and [Organizing Command-Based Robot Projects](https://docs.wpilib.org/en/stable/docs/software/commandbased/organizing-command-based.html#) for additional details on using Command-Based.

### Examples

Expand All @@ -53,12 +52,12 @@ Some large Commands are better represented by several Commands and some Triggers

### Exercises

- Make basic KitBot code using the Command-Based skeleton. You can follow [this](KitbotExampleWalkthrough.md) tutorial.
- Make basic KitBot code using the Command-Based skeleton. You can follow [this](2.5_KitbotExampleWalkthrough.md) tutorial.

### Notes

- We prefer making simple Commands with Command factories, or methods in a subsystem that return a Command.
These methods should be simple interactions like `setTargetExtensionMeters()` or `extendIntake()`.
Then you can use decorators as described [here](https://docs.wpilib.org/en/stable/docs/software/commandbased/command-compositions.html) to compose the basic Commands into more complex sequences.
Generally we make these compositions in `Robot` and `Superstructure` but you can also make single-Subsystem compositions within that Subsystem.
Then, you can use decorators as described [here](https://docs.wpilib.org/en/stable/docs/software/commandbased/command-compositions.html) to compose the basic Commands into more complex sequences.
Generally, we make these compositions in `Robot` and `Superstructure`, but you can also make single-Subsystem compositions within that Subsystem.
See our code from previous years for examples of this pattern, or talk to a software lead.
39 changes: 23 additions & 16 deletions Docs/2_Architecture/2.6_AdvantageKit.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,51 +4,58 @@

### What is logging?

Logging is recording some or all of the state (think the current values of variables, inputs and outputs, and what Commands are running,) of the robot so that we can play it back later.
Logging is recording some or all of the state (such as the current values of variables, inputs and outputs, and what Commands are running) of the robot so that we can play it back later.

### Why log?

Logging helps with debugging by letting us see exactly what the robot was doing when it broke.
This is especially useful at competition when we have limited time and testing ability to diagnose problems.
Logging helps with debugging by letting us see exactly what was happening to the robot and what it was doing when it broke.
This is especially useful at competition, when we have limited time and testing ability to diagnose problems.
For instance, at Houston 2023 we had an issue in our second quals match where our grabber stopped responding to input.
Using the logs of that match, we saw that the sensor readings of the grabber had stopped responding, which suggested that the CAN bus to the grabber had broken.

### Why AdvantageKit?

AdvantageKit logs every input and output to and from the robot, so that we can perfectly recreate the state of the robot in the log or with a simulator.
Logging everything means we never have to say "if only we had logged one more thing!" It also means that we can simulate how the code might have responded differently with changes.
One of the examples 6328 uses is when they adjusted the way they tracked vision targets based on a match log that revealed a problem, then used the log replay to confirm that the change fixed the vision issue.
AdvantageKit is a mature and developed framework for this type of logging, and has been used on Einstein by 6328 and 3476.
The framework should continue to be maintained for the forseeable future and by using the framework instead of a custom solution we reduce our overhead for using a system like this.
AdvantageKit is closely integrated with AdvantageScope, a log and sim viewer built by 6328
AdvantageKit logs every input and output to and from the robot.
This means we can perfectly recreate the state of the robot in the log or with a simulator.

<img alt="Diagram of AKit data flow" src="../../Assets/akit.png" width="800">

It also means that we can run the same inputs through modified code, and simulate how the robot would have responded.
AdvantageKit calls this replay.
One of the examples 6328 uses is when they used a log to diagnose an issue with the way they tracked vision targets, adjusted it, then used replay to confirm that the change would have produced the correct outputs with the same inputs.

AdvantageKit is a mature and developed framework for this type of logging that should continue to be maintained for the foreseeable future.

AdvantageKit is closely integrated with AdvantageScope, a log and sim viewer built by 6328.

### Drawbacks

Running this amount of logging has performance overhead on the rio, using valuable cpu time each loop.
Logging also requires a non-insignificant architecture change to our codebase by using an IO layer under each of our subsystems.
While this does require some additional effort to write subsystems, it also makes simulating subsystems easier so it is a worthwhile tradeoff.

We have not yet done significant on-robot r&d with AdvantageKit and need to assess the performance impacts of using it.
8033-specific usage of AdvantageKit features will be covered in more detail in the next couple of lessons.

### Resources

- [AdvantageKit docs](https://docs.advantagekit.org/)
- [AdvantageKit repository](https://github.com/Mechanical-Advantage/AdvantageKit)
- See the README for this repo for docs
- [AdvantageScope log viewer](https://github.com/Mechanical-Advantage/AdvantageScope)
- [6328 logging talk](https://youtu.be/mmNJjKJG8mw)

### Examples

- [6328 2023 code](https://github.com/Mechanical-Advantage/RobotCode2023)
- [3476 2023 code](https://github.com/FRC3476/FRC-2023)
- [8033 2023 AdvantageKit port](https://github.com/HighlanderRobotics/Charged-Up/tree/advantagekit) [LINK DOWN]
- [8033 2025 code](https://github.com/HighlanderRobotics/Reefscape)

### Exercises

- Install AdvantageKit into your kitbot project following [this tutorial](https://github.com/Mechanical-Advantage/AdvantageKit/blob/45d8067b336c7693e63ee01cdeff0e5ddf50b92d/docs/INSTALLATION.md).
You do not need to modify the subsystem file yet, we will do that as part of the simulation tutorial.
- Install AdvantageKit into your kitbot project following [this tutorial](https://docs.advantagekit.org/getting-started/installation/existing-projects).
You do not need to add the suggested block in the `Robot()` constructor.
We will do that as part of the simulation tutorial.

### Notes

- See also the [Simulation](Simulation.md) article for more on the IO layer structure
- _When we have log files, put a link to one here as an example_
- See the [AdvantageKit Structure Reference](2.7_AKitStructureReference.md) article for more on the IO layer structure
- [Here](https://drive.google.com/drive/folders/1qNMZ7aYOGI31dQNAwt7rhFo97NR7mxtr) are some logs from our 2023-2024 season
2 changes: 1 addition & 1 deletion Docs/2_Architecture/2.9_KitbotExampleWalkthroughSim.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ The first step of moving our standard Command-based code to a loggable, simulate
Luckily AdvantageKit has a handy guide on how to install it on an existing code base.
Follow [this walkthrough](https://github.com/Mechanical-Advantage/AdvantageKit/blob/main/docs/INSTALLATION.md).
Follow all the steps in the doc through adding the `@AutoLog` annotation.
You do not need to add the suggested block in `robotInit()`, instead use the one below.
You do not need to add the suggested block in `Robot()`, instead use the one below.

```Java
Logger.getInstance().recordMetadata("ProjectName", "KitbotExample"); // Set a metadata value
Expand Down
12 changes: 6 additions & 6 deletions Docs/3_Specifics/3.1_ControlsIntro.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,21 @@ Choosing a control strategy is an important takeaway from these articles.
Generally we have a pretty direct tradeoff between time/effort spent on controls and precision in our output (as well as how fast the mechanism gets to that precise output!)
Loosely speaking, there are 3 'levels' of control that we tend to use for our mechanisms.

1. Is simple feedforward control.
### 1. Simple feedforward control.
Really, this is only feedforward in the loosest sense, where we set a DutyCycle or Voltage to the motor.
This sort of control doesn't set the exact speed of the output, and is really only useful on mechanisms that just need some rotation to work, but not anything precise.
You'll usually see this on intakes or routing wheels where we just want to pull a game piece into or through the robot.
The [Intake Subsystem](https://github.com/HighlanderRobotics/Charged-Up/blob/main/src/main/java/frc/robot/subsystems/IntakeSubsystem.java) from 2023 is an example of this.
The [Roller Subsystem](https://github.com/HighlanderRobotics/Reefscape/blob/83a11f1bb1dfd20c04c3dc6a0e548773f11dfc58/src/main/java/frc/robot/subsystems/roller/RollerSubsystem.java#L45) and [RollerIOReal class](https://github.com/HighlanderRobotics/Reefscape/blob/83a11f1bb1dfd20c04c3dc6a0e548773f11dfc58/src/main/java/frc/robot/subsystems/roller/RollerIOReal.java#L99) from 2025 is an example of this.

2. Is simple feedback control.
### 2. Simple feedback control.
We tend to use this on mechanisms that we might want to use sensible units for (like rotations per minute, or degrees) instead of an arbitrary output but don't need huge amounts of precision or are so overpowered compared to the forces on them that we can ignore outside forces.
Often we use this by calling a TalonFX's Position or Velocity control modes.
[The angle motor on a swerve module](https://github.com/HighlanderRobotics/Charged-Up/blob/main/src/main/java/frc/robot/SwerveModule.java) is an example of this sort of control, and works because the Falcon 500 powering the module angle is so much stronger than the friction of the wheel with the ground.
[The angle motor on a swerve module](https://github.com/HighlanderRobotics/Reefscape/blob/83a11f1bb1dfd20c04c3dc6a0e548773f11dfc58/src/main/java/frc/robot/subsystems/swerve/ModuleIOReal.java#L203) is an example of this sort of control, and works because the Kraken X60 powering the module angle is so much stronger than the friction of the wheel with the ground.

3. Is combined feedforward and feedback control.
### 3. Combined feedforward and feedback control.
This is ideal for most situations where we desire precise control of a mechanism, and should be used on all primary mechanisms of a robot.
It tends to require more effort to tune and model than the previous levels, but is the correct way to control mechanisms.
The [Elevator Subsystem](https://github.com/HighlanderRobotics/Charged-Up/blob/main/src/main/java/frc/robot/subsystems/ElevatorSubsystem.java) from 2023 is an example of this, specifically the `updatePID()` method which adds the results of a PID controller calculation with a feedforward controller calculation.
The [Elevator Subsystem](https://github.com/HighlanderRobotics/Charged-Up/blob/4475dfc7e07efa000e87597dddaac1e75c28a29c/src/main/java/frc/robot/subsystems/Elevator/ElevatorSubsystem.java#L49) from 2023 is an example of this, specifically the `updatePID()` method which adds the results of a PID controller calculation with a feedforward controller calculation.
Notice the use of a WPILib feedforward class here.
WPILib provides several classes that model common mechanisms.
[This article](https://docs.wpilib.org/en/stable/docs/software/advanced-controls/controllers/feedforward.html#feedforward-control-in-wpilib) goes over the classes in more detail.
Expand Down
Loading