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
2,204 changes: 0 additions & 2,204 deletions .idea/caches/deviceStreaming.xml

This file was deleted.

129 changes: 129 additions & 0 deletions src/content/docs/your-first-robot/auto.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
---
title: Your First Autonomous
description: Combining commands and Pedro Pathing into a working autonomous OpMode.
sidebar:
order: 6
---

import { Tabs, TabItem } from "@astrojs/starlight/components";

An autonomous OpMode uses `@NextAutonomous` instead of `@NextTeleop`, and instead of binding commands to gamepad buttons, you schedule a routine when the OpMode starts.
This routine can combine your mechanism commands with driving, using Pedro Pathing.

## Pedro commands

Ivy includes built-in commands for controlling your robot's movement using [Pedro Pathing](https://pedropathing.com/).

`follow` makes the robot follow a `PathChain`, and finishes once the follower is no longer busy.

<Tabs syncKey="language">
<TabItem label="Kotlin">

```kotlin
val goToScore: Command = follow(follower, scorePath)
```

</TabItem>
<TabItem label="Java">

```java
Command goToScore = follow(follower, scorePath);
```

</TabItem>
</Tabs>

## Building the routine

Because `follow` is a command just like any other, it fits right into a `SequentialGroup` alongside your mechanism commands.
Here, the robot drives to `scorePath`'s end, then intakes, then fires.
It's common to keep routines like this in their own class, separate from your OpMode:

<Tabs syncKey="language">
<TabItem label="Kotlin">

```kotlin
class Routines(val robot: MyRobot, val follower: Follower) {

fun autoRoutine(): Command = SequentialGroup(
follow(follower, scorePath),
robot.intake.intake(),
robot.launch()
)

}
```

</TabItem>
<TabItem label="Java">

```java
public class Routines {

private final MyRobot robot;
private final Follower follower;

public Routines(MyRobot robot, Follower follower) {
this.robot = robot;
this.follower = follower;
}

public Command autoRoutine() {
return new SequentialGroup(
follow(follower, scorePath),
robot.intake.intake(),
robot.launch()
);
}

}
```

</TabItem>
</Tabs>

## Creating the OpMode

Schedule the routine when the OpMode starts:

<Tabs syncKey="language">
<TabItem label="Kotlin">

```kotlin
@NextAutonomous(name = "My Autonomous")
class MyAutonomous(robot: MyRobot) : NextOpMode(robot) {

val robot = robot

init {
val routines = Routines(robot, follower)
routines.autoRoutine().schedule()
}

}
```

</TabItem>
<TabItem label="Java">

```java
@NextAutonomous(name = "My Autonomous")
public class MyAutonomous extends NextOpMode {

private final MyRobot robot;

public MyAutonomous(MyRobot robot) {
super(robot);
this.robot = robot;

Routines routines = new Routines(robot, follower);
routines.autoRoutine().schedule();
}

}
```

</TabItem>
</Tabs>

That's it, you've gone from a creating your first mechanism all the way to a full autonomous OpMode.
19 changes: 18 additions & 1 deletion src/content/docs/your-first-robot/index.mdx
Original file line number Diff line number Diff line change
@@ -1,6 +1,23 @@
---
title: Your First Robot
description: A guided tutorial for programming your first robot with NextFTC.
sidebar:
order: 1
---

Content coming soon.
This tutorial will walk you through creating a subsystem all the way to creating an OpMode.
You'll write commands, group those commands into routines, and put everything together into a real autonomous OpMode, including following a path with Pedro Pathing.

## What's in this tutorial

- **Commands**
Writing individual actions your subsystem can perform.

- **Command Groups**
Sequencing and combining commands into full routines.

- **Autonomous**
Assembling everything into a working autonomous OpMode.

- **Pedro Pathing**
Following a path as part of your autonomous routine.
107 changes: 107 additions & 0 deletions src/content/docs/your-first-robot/mechanism.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
---
title: Your First Mechanism
description: Wrapping your hardware into a mechanism and controlling it with commands.
sidebar:
order: 3
---

import { Tabs, TabItem } from "@astrojs/starlight/components";
import { Aside } from "@astrojs/starlight/components";

A mechanism groups the hardware that makes up one part of your robot like an intake, along with the commands that control it.

## Defining your Mechanism and Hardware

Start first by creating your class that implements Mechanism.
Then declare the hardware your mechanism uses.
Here's an intake with a motor and a servo.

<Tabs syncKey="language">
<TabItem label="Kotlin">

```kotlin
class Intake : Mechanism {

val intakeMotor = NextMotor(RobotController.controlHub(), 2)
val intakeServo = NextServo(RobotController.controlHub(), 4)

}
```

</TabItem>
<TabItem label="Java">

```java
public class Intake implements Mechanism {

NextMotor intakeMotor = new NextMotor(RobotController.controlHub(), 2);
NextServo intakeServo = new NextServo(RobotController.controlHub(), 4);

}
```

</TabItem>
</Tabs>

<Aside type="tip" title="">
When possible, use a direct Lynx Module accessor like above, it skips the
hardware map lookup and saves you a step in creating a config.
</Aside>

## Writing commands

Instead of tracking a state machine and constantly sending hardware, each command just sets the hardware directly when it's scheduled.
You can use `instant` commands for the actions your intake will do, and `instant` command will run once and finish instantly.

<Tabs syncKey="language">
<TabItem label="Kotlin">

```kotlin
fun start(): Command = instant {
intakeMotor.setThrottle(FORWARD_SPEED)
intakeServo.setPosition(INTAKE_POS)
}

fun reverse(): Command = instant {
intakeMotor.setThrottle(REVERSE_SPEED)
intakeServo.setPosition(LIFT_POS)
}

fun off(): Command = instant {
intakeMotor.setThrottle(OFF_SPEED)
intakeServo.setPosition(LIFT_POS)
}
```

</TabItem>
<TabItem label="Java">

```java
public Command start() {
return instant(() -> {
intakeMotor.setThrottle(FORWARD_SPEED);
intakeServo.setPosition(INTAKE_POS);
});
}

public Command reverse() {
return instant(() -> {
intakeMotor.setThrottle(REVERSE_SPEED);
intakeServo.setPosition(LIFT_POS);
});
}

public Command off() {
return instant(() -> {
intakeMotor.setThrottle(OFF_SPEED);
intakeServo.setPosition(LIFT_POS);
});
}
```

</TabItem>
</Tabs>

## What's next

Next we will walk through how to set up your `NextRobot`, where you're able to register mechanisms and make different mechanisms to work together across every OpMode.
97 changes: 97 additions & 0 deletions src/content/docs/your-first-robot/robot.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
---
title: Your First NextRobot
description: Setting up your NextRobot to register mechanisms and share them across every OpMode.
sidebar:
order: 4
---

import { Tabs, TabItem } from "@astrojs/starlight/components";
import { Aside } from "@astrojs/starlight/components";

Your `NextRobot` is where all your mechanisms come together.
It's shared across every OpMode, so instead of re-creating your mechanisms in each one, you register them once here.

## Defining your robot

Create a class that implements `NextRobot`, and add an instance of each mechanism as a field:

<Tabs syncKey="language">
<TabItem label="Kotlin">

```kotlin
class MyRobot : NextRobot {

val intake = Intake()
val transfer = Transfer()
val launcher = Launcher()

override fun getMechanisms(): Set<Mechanism> {
return setOf(intake, transfer, launcher)
}

}
```

</TabItem>
<TabItem label="Java">

```java
public class MyRobot implements NextRobot {

public final Intake intake = new Intake();
public final Transfer transfer = new Transfer();
public final Launcher launcher = new Launcher();

@Override
public Set<Mechanism> getMechanisms() {
return Set.of(intake, transfer, launcher);
}

}
```

</TabItem>
</Tabs>

## Coordinating Mechanisms

Because every mechanism lives on the same `robot`, they can reference each other directly.
This is how you make mechanisms work together, for example, having the transfer kicker kick once the launcher`s up to speed:

<Tabs syncKey="language">
<TabItem label="Kotlin">

```kotlin
fun launch(): Command = SequentialGroup(
launcher.start(),
transfer.kick(),
intake.start()
)
```

</TabItem>
<TabItem label="Java">

```java
public Command launch() {
return new SequentialGroup(
launcher.start(),
transfer.kick(),
intake.start()
);
}
```

</TabItem>
</Tabs>

<Aside type="note" title="TODO">
<Aside type="tip" title="">
For setting up your drivetrain, refer to the [drive
utils](/*/robot/drive-util/*/) page.
</Aside>
</Aside>

## What's next

Next, you'll learn how to create your first tele op with v2.
18 changes: 18 additions & 0 deletions src/content/docs/your-first-robot/setup.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
title: Setup
description: Getting your project ready before starting this tutorial.
sidebar:
order: 2
---

Before starting this tutorial, there are a couple things you'll want to have setup: NextFTC installed in your project, and your project organized in a way you want.

## Installing NextFTC

If you haven't added NextFTC to your project yet, head over to the [Installation](/introduction/installation/) page.
It walks through adding the dependencies to your `build.gradle` and getting everything available for you to use in your project.

## Structuring your project

NextFTC doesn't require any specific project layout, but it helps to have a consistent one.
The [Robot Project Structure](/robot/project-structure/#suggested-not-required-layout) shows an example of how you might organize your `NextRobot`, subsystems, and OpModes.
Loading
Loading