Skip to content
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
6,882 changes: 6,882 additions & 0 deletions package-lock.json

Large diffs are not rendered by default.

Binary file added public/stage1/commands/2910-robot.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 public/stage1/commands/human-flow-diagram.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 public/stage1/commands/robot-flow-diagram.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 12 additions & 0 deletions src/config/sidebarConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,18 @@ export const sidebarSections: Record<string, SidebarSection[]> = {
},
],

'/section-2-commands': [
{
label: 'Section 2: Commands',
items: [
{ label: 'The Concepts', slug: 'section-2-commands/command-based-overview' },
{ label: 'The Body of a Command', slug: 'section-2-commands/the-command-body' },
{ label: 'Commands & Mechanisms, Pt. 1', slug: 'section-2-commands/commands-and-mechanisms' },
{ label: 'Defining Triggers', slug: 'section-2-commands/triggers' },
{ label: 'Commands & Mechanisms, Pt. 2', slug: 'section-2-commands/commands-and-mechanisms-pt2' },
],
}
],
// Intro To Java section
'/intro-to-java': [
{
Expand Down
54 changes: 54 additions & 0 deletions src/content/docs/section-2-commands/command-based-kitbot.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
---
title: The Command Scheduler
description: How to use the command scheduler
prev: section-2-commands/why-mechanisms
next: false
---
import Aside from '../../../components/Aside.astro';

# Task 1: Setup

Add the `Scheduler.getDefault().run()` statement in the `Robot` class.
This allows for commands to function.

```java
public class Robot extends TimedRobot {
@Override
public void robotPeriodic() {
Scheduler.getDefault().run();
}
}
```

# Task 2: The Feeder Mechanism

Write a feeder mechanism within the `Feeder.java` file. It should contain:

1. A private `TalonFX` motor controller object, with ID 0 and a systemcore CANBus of ID 0
2. A `feed()` command that waits 2 seconds, then sets the throttle of the motor to 1.0 forever.
3. A `intake()` command that sets the throttle of the motor to -1.0 forever.

# Task 3: The IntakeLauncher Mechanism

Write an intake launcher mechanism within the `IntakeLauncher.java` file. It should contain:

1. A private `TalonFX` motor controller object, with ID 1 and a systemcore CANBus of ID 0
2. A `shoot()` command that waits 2 seconds, then sets the throttle of the motor to 1.0 forever.
3. A `intake()` command that sets the throttle of the motor to -1.0 forever.

# Task 4: The Superstructure Mechanism

Combine the intake launcher and feeder mechanisms into a `Superstructure` mechanism
within the `Superstructure.java` file. It should contain:

1. Private instances of the `IntakeLauncher` and `Feeder` classes
2. A `shoot()` command that runs the `feeder.feed()` and `intakeLauncher.shoot()` commands in parallel
3. A `intake()` command that runs the `feeder.intake()` and `intakeLauncher.intake()` commands in parallel

# Task 5: The Drivetrain Mechanism

TODO

# Task 6: Button Bindings and Autonomous

TODO
73 changes: 73 additions & 0 deletions src/content/docs/section-2-commands/command-based-overview.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
---
title: The Concepts of Command-Based Programming
description: The what, how, and why of commands
prev: false
next: section-2-commands/the-command-body
---
import Aside from '../../../components/Aside.astro';
import ContentImage from '../../../components/ContentImage.astro';

### What is Command-Based Programming?

Up until now, most of the code you've written has been akin to a
set of instructions (execute this task, then this, and finally this).
However, robots (and humans!) don't just execute a set of tasks and shut down.

Imagine your daily routine. When an alarm clock rings, you turn it off and tumble out of bed.
When your belly rumbles, you walk to the fridge and get a snack. When the clock strikes 8 AM,
you open the front door to leave for school.

<ContentImage src="/stage1/commands/human-flow-diagram.png" />

Notice how none of these actions had a predefined order; rather, they were a reaction to
to certain kinds of stimuli.

Command-based programming models robot behavior in a similar way.
1. It defines behaviors/actions(tumbling out of bed, getting a snack, etc.) as `Command`s.
2. It defines the stimuli that trigger these behaviors (a ringing alarm clock, a rumbling belly, etc.) as `Trigger`s.

For instance, a command-based robot might have the following structure:

<ContentImage src="/stage1/commands/robot-flow-diagram.png" />

Here, everything on the left is a `Trigger`, while everything on the right is a `Command`.

<Aside type="note">
We say that triggers "schedule" commands.
So, the "y button pressed" trigger would schedule the "Run Intake Motor" command.
In a similar way, commands are "bound" to triggers -
</Aside>

### Mechanisms and Priority

However, the structure of using `Command`s to represent behaviors misses an important component.

Think back to the human example: you’re walking to the fridge, but the clock hits 8 AM before you get there.
You can't do both at once, since both actions require your arms and legs. So, you stop and leave for school.

Next, the robot. If the X and Y buttons are held, the shooter and intake motors should both run.
But if the X and A buttons are held, the robot code must choose between running the shooter
at a fast speed or a slow speed.

Command-Based models this relationship with 2 concepts: Mechansisms and Priority.

##### Mechanisms
A Mechanism is a robot component whose state can be updated through commands. `Command`s declare
the mechanisms they require - thus, mechanisms are also called "requirements".

An intake is a mechanism because your code controls its speed. On the other hand,
an apriltag camera wouldn't be because your code only reads data from it, but doesn't update its state.

<Aside type="note">
In the human case, your arms and legs would be mechanisms, but your ears wouldn't be.
</Aside>

##### Priority
When 2 commands share one or more requirements, priority determines which command
should be cancelled and which command should continue.

In the human example, the "leave for school" `Command` would have a higher priority
than the "get a snack" `Command`.

Priority is represented as an `int`. Commands default to a priority of 0, and a
larger number represents a higher priority.
151 changes: 151 additions & 0 deletions src/content/docs/section-2-commands/commands-and-mechanisms-pt2.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
---
title: Commands and Mechanisms, Part 2
description: Intermediate-level uses of commands and mechanisms
prev: section-2-commands/the-command-body
next: section-2-commands/why-mechanisms
---
import ContentImage from '../../../components/ContentImage.astro';

### Adding Delays to Commands
Use `coroutine.wait()` to wait for a predefined amount of time:
```java
public Command wait5SecsThenPrintHi() {
return run(coroutine -> {
coroutine.wait(Seconds.of(5));
System.out.println("This will show up 5 seconds later.");
})
}
```

### Running Commands in parallel
`coroutine.awaitAll(a, b, c)` will run the commands a, b, and c in parallel,
waiting for all 3 to finish before proceeding.

```java
public class Intake implements Mechanism {
private final TalonFX motor = new TalonFX(0);

private Command deployIntake() { ... }
private Command runIntakeRollers() { ... }

public Command parallelCommands() {
return run(coroutine -> {
coroutine.awaitAll(
deployPivot(),
runIntakeRollers()
);
})
.named("Parallel Commands");
}
}
```

On the other hand, `coroutine.awaitAny(a, b, c)` runs a, b, and c in parallel
until any of a, b, or c finishes. Then, it will cancel the remaining commands.

### A more concrete definition of Mechanisms

We've previously defined a `Mechanism` as a component of the robot. However,
there are many ways you can define "robot component".

Let's think of a pivoting arm, like the one below:

<ContentImage src="/stage1/commands/2910-robot.png" width="60%" />

Should the entire arm be one mechanism? Or should the pivot (bottom joint),
wrist (top joint) and intake be separate mechanisms? Well, the answer is both!

```java
public class Arm implements Mechanism {
private Wrist wrist = new Wrist();
private Pivot pivot = new Pivot();
private Intake intake = new Intake();
}
```

In separate files, you would define `Intake`, `Pivot`, and `Wrist` as mechanisms too.
The idea is that each "sub-mechanism" would define it's own commands:

##### Intake.java
```java
public class Intake implements Mechanism {
public Intake() {
setDefaultCommand(stop());
}

public Command stop() { ... }
public Command outtake() { ... }
}
```

##### Pivot.java
```java
public class Pivot implements Mechanism {
public Pivot() {
setDefaultCommand(stop());
}

public Command stop() { ... }
public Command moveToScorePosition() { ... }
}
```

##### Arm.java
```java
public class Arm implements Mechanism {
public Arm() {
setDefaultCommand(stop());
}

public Command stop() { ... }
public Command moveToScorePosition() { ... }
}
```

Then, the `Arm` mechanism will compose, or combine, these commands together.
```java
public class Arm implements Mechanism {
private Wrist wrist = new Wrist();
private Pivot pivot = new Pivot();
private Intake intake = new Intake();

public Command stop() {
return run(coroutine -> {
// Stop the wrist, pivot, and intake at once
coroutine.awaitAll(wrist.stop(), pivot.stop(), intake.stop());
})
.named("Stop Arm");
}

public Command score() {
return run(coroutine -> {
// Wait until pivot & wrist are at scoring position
coroutine.awaitAll(
pivot.moveToScorePosition(),
wrist.moveToScorePosition()
);
// Then, run the intake
coroutine.await(intake.outtake());
})
.named("Score Gamepiece");
}
}
```

This `Arm` mechanism can also be called a "superstructure" because it groups
many mechanisms together.

### Commands without requirements

Sometimes, you need to create a command that doesn't require any mechanisms.
To do so, you can replace `run(...)` with `Command.noRequirements(...)`.
```java
public class Robot {
private Command justPrintHi() {
return Command.noRequirements(coroutine -> {
System.out.println("Hello World!");
})
.named("Hello World!");
}
}
```
Loading
Loading