Skip to content

Commit d6a0663

Browse files
committed
add robot module documentation
1 parent 6076d26 commit d6a0663

7 files changed

Lines changed: 611 additions & 4 deletions

File tree

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
---
2+
title: Commands
3+
description: How NextFTC schedules commands, and where to find the full command API.
4+
sidebar:
5+
order: 1
6+
---
7+
8+
import { Tabs, TabItem } from "@astrojs/starlight/components";
9+
10+
NextFTC doesn't define its own command framework.
11+
Instead, the `robot` module builds directly on top of [Ivy](https://pedropathing.com/docs/ivy),
12+
Pedro Pathing's command-based scheduling library.
13+
If you've used Ivy, WPILib commands, or NextFTC v1's command system before,
14+
this will feel familiar.
15+
16+
This page covers the small surface of Ivy that the `robot` module touches directly.
17+
For the full command API, such as sequential and parallel groups, `Command.Builder`, and everything else,
18+
see [Ivy's documentation](https://pedropathing.com/docs/ivy).
19+
20+
## Building commands from a Mechanism
21+
22+
The most common way to create a command is through [`Mechanism.instant`](/robot/mechanisms/) and
23+
[`Mechanism.infinite`](/robot/mechanisms/), which wrap Ivy's `Commands.instant`/`Commands.infinite` and
24+
automatically call `requiring(this)`, so the scheduler knows the command owns that mechanism's hardware:
25+
26+
<Tabs syncKey="language">
27+
<TabItem label="Kotlin">
28+
29+
```kotlin
30+
class Intake : Mechanism {
31+
val motor = NextMotor("intakeMotor")
32+
33+
fun run() = infinite { motor.throttle = 1.0 }
34+
fun stop() = instant { motor.throttle = 0.0 }
35+
}
36+
```
37+
38+
</TabItem>
39+
<TabItem label="Java">
40+
41+
```java
42+
public class Intake implements Mechanism {
43+
NextMotor motor = new NextMotor("intakeMotor");
44+
45+
public Command run() { return infinite(() -> motor.setThrottle(1.0)); }
46+
public Command stop() { return instant(() -> motor.setThrottle(0.0)); }
47+
}
48+
```
49+
50+
</TabItem>
51+
</Tabs>
52+
53+
A command built with `infinite` keeps running (recomputing its body every loop) until it's cancelled,
54+
useful for anything driven continuously by gamepad input.
55+
`instant` runs its body once and finishes immediately.
56+
57+
## Checking and cancelling commands
58+
59+
Two `Command` members you'll reach for often, both from Ivy:
60+
`isScheduled` (whether the command is currently running) and `cancel()` (stop it early).
61+
You'll see these used by [triggers](/robot/triggers/) to start and stop commands in response to gamepad input.
62+
63+
## Learn more
64+
65+
For everything else, such as composing commands into sequences and parallel groups,
66+
writing custom commands from scratch, and the full `Scheduler` API,
67+
head to [Ivy's documentation](https://pedropathing.com/docs/ivy).

src/content/docs/robot/index.mdx

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,36 @@
11
---
22
title: Robot Module
33
description: NextRobot, OpModes, Mechanisms, Triggers, and the rest of the robot module.
4+
sidebar:
5+
order: 0
46
---
57

8+
import { CardGrid, LinkCard } from "@astrojs/starlight/components";
9+
610
The `robot` module is where everything comes together:
711
your robot, your subsystems, your OpModes, and your gamepad bindings.
812
It builds on top of `hardware` and `control`, and provides the command-based scheduling
913
layer (via [PedroPathing Ivy](https://pedropathing.com/docs/ivy)) that ties them all to your gamepad.
1014

11-
- **`NextRobot`**: the root of your robot, auto-discovered and instantiated for you.
12-
- **`Mechanism`**: a subsystem, like an arm or a claw, that exposes its behavior as commands.
13-
- **`NextOpMode`**: the base class for your OpModes, paired with the `@NextTeleop`/`@NextAutonomous` annotations.
14-
- **`Trigger`, `RangeTrigger`, and `CommandGamepad`**: bind gamepad input directly to commands.
15+
<CardGrid>
16+
<LinkCard
17+
title="Mechanisms"
18+
href="/robot/mechanisms/"
19+
description="Grouping hardware and behavior into reusable subsystems."
20+
/>
21+
<LinkCard
22+
title="NextRobot"
23+
href="/robot/nextrobot/"
24+
description="The root of your robot, auto-discovered and shared across every OpMode."
25+
/>
26+
<LinkCard
27+
title="NextOpMode"
28+
href="/robot/nextopmode/"
29+
description="The base class for your OpModes, with the gamepad, telemetry, and hardware map ready to go."
30+
/>
31+
<LinkCard
32+
title="Project Structure"
33+
href="/robot/project-structure/"
34+
description="How NextFTC discovers your NextRobot and OpModes."
35+
/>
36+
</CardGrid>
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
---
2+
title: Mechanisms
3+
description: Grouping hardware and behavior into reusable subsystems with Mechanism.
4+
sidebar:
5+
order: 2
6+
---
7+
8+
import { Tabs, TabItem } from "@astrojs/starlight/components";
9+
10+
A `Mechanism` represents a subsystem on your robot, an arm, a claw, a drivetrain, bundling the hardware it
11+
owns with the commands and periodic logic that control it.
12+
13+
<Tabs syncKey="language">
14+
<TabItem label="Kotlin">
15+
16+
```kotlin
17+
interface Mechanism {
18+
fun periodic() {}
19+
fun instant(action: Runnable): Command
20+
fun infinite(action: Runnable): Command
21+
}
22+
```
23+
24+
</TabItem>
25+
<TabItem label="Java">
26+
27+
```java
28+
public interface Mechanism {
29+
default void periodic() {}
30+
Command instant(Runnable action);
31+
Command infinite(Runnable action);
32+
}
33+
```
34+
35+
</TabItem>
36+
</Tabs>
37+
38+
## `periodic()`
39+
40+
Called once per loop for every mechanism registered on your [`NextRobot`](/robot/nextrobot/)'s `mechanisms` set.
41+
Use it for anything that needs to run continuously regardless of what commands are active,
42+
such as reading a sensor, running a background PID loop to hold position, and so on.
43+
44+
## `instant` and `infinite`
45+
46+
Both build an [Ivy](/robot/commands/) command scoped to the mechanism,
47+
automatically calling `requiring(this)` so the scheduler treats it as exclusive to that mechanism.
48+
This means that two commands can't fight over the same hardware at once.
49+
`instant` runs its action once;
50+
`infinite` re-runs its action every loop until cancelled.
51+
52+
## Example: a simple mechanism
53+
54+
<Tabs syncKey="language">
55+
<TabItem label="Kotlin">
56+
57+
```kotlin
58+
class Claw : Mechanism {
59+
val servo = NextServo("clawServo")
60+
61+
fun open() = instant { servo.position = 0.2 }
62+
fun close() = instant { servo.position = 0.8 }
63+
}
64+
```
65+
66+
</TabItem>
67+
<TabItem label="Java">
68+
69+
```java
70+
public class Claw implements Mechanism {
71+
NextServo servo = new NextServo("clawServo");
72+
73+
public Command open() { return instant(() -> servo.setPosition(0.2)); }
74+
public Command close() { return instant(() -> servo.setPosition(0.8)); }
75+
}
76+
```
77+
78+
</TabItem>
79+
</Tabs>
80+
81+
## Example: using `periodic()` for continuous logic
82+
83+
A mechanism can use `periodic()` for anything that needs to run every loop,
84+
independent of whatever command is currently active.
85+
For example, an intake that automatically stops once a sensor reports it has a piece:
86+
87+
<Tabs syncKey="language">
88+
<TabItem label="Kotlin">
89+
90+
```kotlin
91+
class Intake : Mechanism {
92+
val motor = NextMotor("intakeMotor")
93+
val sensor = NextDistanceSensor("intakeSensor")
94+
95+
override fun periodic() {
96+
sensor.update()
97+
if (sensor.isWithinDistance(2.0)) {
98+
motor.throttle = 0.0
99+
}
100+
}
101+
102+
fun run() = instant { motor.throttle = 1.0 }
103+
}
104+
```
105+
106+
</TabItem>
107+
<TabItem label="Java">
108+
109+
```java
110+
public class Intake implements Mechanism {
111+
NextMotor motor = new NextMotor("intakeMotor");
112+
NextDistanceSensor sensor = new NextDistanceSensor("intakeSensor");
113+
114+
@Override
115+
public void periodic() {
116+
sensor.update();
117+
if (sensor.isWithinDistance(2.0)) {
118+
motor.setThrottle(0.0);
119+
}
120+
}
121+
122+
public Command run() {
123+
return instant(() -> motor.setThrottle(1.0));
124+
}
125+
}
126+
```
127+
128+
</TabItem>
129+
</Tabs>
130+
131+
Register the mechanism on your [`NextRobot`](/robot/nextrobot/) so its `periodic()` gets called every loop.
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
---
2+
title: NextOpMode
3+
description: The base class for your OpModes, with the gamepad, telemetry, and hardware map ready to go.
4+
sidebar:
5+
order: 4
6+
---
7+
8+
import { Tabs, TabItem, Aside } from "@astrojs/starlight/components";
9+
10+
`NextOpMode` is the base class for every OpMode you write with NextFTC.
11+
It wraps the FTC SDK's `LinearOpMode`,
12+
automatically wires up your [`NextRobot`](/robot/nextrobot/),
13+
and drives the command scheduler and [triggers](/robot/triggers/) for you every loop.
14+
15+
## Fields
16+
17+
Every `NextOpMode` exposes these directly, no `hardwareMap.get(...)` boilerplate required:
18+
19+
- **`gamepad1`** / **`gamepad2`** — the standard FTC `Gamepad` objects.
20+
- **`telemetry`** — the standard FTC SDK `Telemetry`.
21+
- **`hardwareMap`** — the standard FTC SDK `HardwareMap`.
22+
23+
## Lifecycle
24+
25+
Override whichever of these you need — all are optional:
26+
27+
| Method | Called |
28+
| -------------------- | ------------------------------------------------ |
29+
| `disabledPeriodic()` | Repeatedly, while the Driver Station is in INIT. |
30+
| `start()` | Once, right after the PLAY button is pressed. |
31+
| `periodic()` | Repeatedly, while the OpMode is running. |
32+
| `end()` | Once, when the OpMode finishes. |
33+
34+
<Tabs syncKey="language">
35+
<TabItem label="Kotlin">
36+
37+
```kotlin
38+
@NextTeleop(name = "My Teleop")
39+
class MyTeleop(robot: MyRobot) : NextOpMode(robot) {
40+
override fun periodic() {
41+
Telemetry.log("Status", "Running")
42+
}
43+
}
44+
```
45+
46+
</TabItem>
47+
<TabItem label="Java">
48+
49+
```java
50+
@NextTeleop(name = "My Teleop")
51+
public class MyTeleop extends NextOpMode {
52+
public MyTeleop(MyRobot robot) { super(robot); }
53+
54+
@Override
55+
public void periodic() {
56+
Telemetry.log("Status", "Running");
57+
}
58+
}
59+
```
60+
61+
</TabItem>
62+
</Tabs>
63+
64+
Take your `NextRobot` as a constructor parameter and pass it straight to `super(...)`.
65+
NextFTC's scanner instantiates your OpMode and injects the discovered robot instance for you,
66+
so you never construct `MyRobot` yourself.
67+
See [NextFTC robot project structure](/robot/project-structure/) for the full injection rules.
68+
69+
Bind gamepad input to your mechanisms' commands from `start()`;
70+
see [Triggers and RangeTriggers](/robot/triggers/) for the full binding API.
71+
72+
## What NextOpMode does for you automatically
73+
74+
You'll never need to call these yourself, as `NextOpMode` runs them every loop behind the scenes:
75+
76+
- Calls `periodic()` on your `NextRobot` and every one of its mechanisms.
77+
- Polls triggers and executes the Ivy scheduler, so bound commands actually run.
78+
- Updates motor control loops.
79+
- Flushes telemetry.
80+
81+
## `BulkReadHook`
82+
83+
One additional behavior is opt-in rather than automatic:
84+
bulk-reading hardware from your control/expansion hubs.
85+
Pass `BulkReadHook` as an extra constructor argument to switch your Lynx modules to manual bulk-caching mode and have the cache cleared for you every loop:
86+
87+
<Tabs syncKey="language">
88+
<TabItem label="Kotlin">
89+
90+
```kotlin
91+
class MyTeleop(robot: MyRobot) : NextOpMode(robot, BulkReadHook)
92+
```
93+
94+
</TabItem>
95+
<TabItem label="Java">
96+
97+
```java
98+
public class MyTeleop extends NextOpMode {
99+
public MyTeleop(MyRobot robot) { super(robot, BulkReadHook.INSTANCE); }
100+
}
101+
```
102+
103+
</TabItem>
104+
</Tabs>
105+
106+
## Registering with the Driver Station
107+
108+
Annotate your class with `@NextTeleop` or `@NextAutonomous` to make it selectable on the Driver Station.
109+
Both are picked up automatically, just like the `@TeleOp` and `@Autonomous` annotations in the FTC SDK.
110+
See [NextFTC robot project structure](/robot/project-structure/) for how this discovery works.
111+
112+
<Aside type="note">
113+
`@NextTeleop(name, group)` and `@NextAutonomous(name, group, preselectTeleop)`
114+
both default `name` to the class name. `group` defaults to `"NextFTC Teleop"`
115+
or `"NextFTC Auto"` respectively. `preselectTeleop` lets an autonomous OpMode
116+
suggest which teleop the Driver Station should switch to afterward.
117+
</Aside>

0 commit comments

Comments
 (0)