-
Notifications
You must be signed in to change notification settings - Fork 22
Flywheel example #19
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
base: main
Are you sure you want to change the base?
Flywheel example #19
Conversation
BeepBot99
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall good, some changes requested. In addition to the requested changes, could you link to the WPILib flywheel tuning page somewhere on each of the added pages? Maybe on the guide page it could go in the "make sure to tune your controller" callout.
Also, flywheel.md will not show up in the sidebar. You need to edit the configuration files. You should clone the repo and run npm install and npm run dev (or use the package manager of your choice) to preview the docs locally.
| If you're using a command-based framework like NextFTC, | ||
| you can create commands that spin the flywheel up or shut it down. | ||
|
|
||
| An example of a Flywheel subsystem using NextControl can be found |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The example on this page should be without NextFTC, as NextControl does not depend on NextFTC. See the slides page.
| ```kotlin | ||
| controlSystem { | ||
| velPid(0.005, 0.0, 0.0) | ||
| basicFF(0.01, 0.02, 0.03) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know these are the numbers used in NextFTC/Examples, but in this case, kA in basicFF is actually unused, so it should be replaced with 0.
| here will learn how to program your own flywheel subsystem. | ||
|
|
||
| > [!TIP] | ||
| > This subsystem can be generalized to any subsystem with a motor. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be "to any subsystem with a motor whose velocity needs to be controlled," or something along those lines.
| @@ -0,0 +1,231 @@ | |||
| # Flywheel Subsystem | |||
|
|
|||
| A subsystem that is found in almost all FTC robots in most seasons is a flywheel, | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Most seasons is not true. (Although it is true of every season you've competed in.)
| > [!TIP] | ||
| > This subsystem can be generalized to any subsystem with a motor. | ||
|
|
||
| ## Step 1: Create your subsystem |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Capitalize "subsystem."
| # Flywheel Subsystem | ||
|
|
||
| A subsystem that is found in almost all FTC robots in most seasons is a flywheel, | ||
| here will learn how to program your own flywheel subsystem. | ||
|
|
||
| > [!TIP] | ||
| > This subsystem can be generalized to any subsystem with a motor. | ||
|
|
||
| ## Step 1: Create your subsystem | ||
|
|
||
| The first step to creating your subsystem is setting up the structure for it. | ||
| There should only be one instance of each | ||
| subsystem. To do this, we will make our subsystem | ||
| a [singleton](https://www.geeksforgeeks.org/singleton-design-pattern/). | ||
|
|
||
| :::tabs key:codes | ||
|
|
||
| == Kotlin | ||
|
|
||
| Creating our subsystem with the `object` keyword makes it a singleton: | ||
|
|
||
| ```kotlin | ||
| object Flywheel : Subsystem { | ||
|
|
||
| } | ||
| ``` | ||
|
|
||
| == Java | ||
| In Java, there are a couple lines of boilerplate you will need to add to the top | ||
| of every subsystem you create to | ||
| make it a singleton: | ||
|
|
||
| ```java | ||
| public class Flywheel implements Subsystem { | ||
| public static final Flywheel INSTANCE = new Flywheel(); | ||
| private Flywheel() { } | ||
|
|
||
| } | ||
| ``` | ||
|
|
||
| ::: | ||
|
|
||
| ## Step 2: Create your motor | ||
|
|
||
| Next, we need to set up a motor to power our flywheel. Let's start by creating a | ||
| variable to store our motor. It should be | ||
| of type `MotorEx`. | ||
|
|
||
| :::tabs key:code | ||
|
|
||
| == Kotlin | ||
|
|
||
| ```kotlin | ||
| private val motor = MotorEx("flywheel_motor") | ||
| ``` | ||
|
|
||
| == Java | ||
|
|
||
| ```java | ||
| private MotorEx motor = new MotorEx("flywheel_motor"); | ||
| ``` | ||
|
|
||
| ::: | ||
|
|
||
| We also need a `ControlSystem`, since we want to move our motor. We'll be | ||
| using [NextControl](/control), NextFTC's | ||
| solution to control in FTC. NextControl makes it very easy to create more | ||
| complex controllers if you ever need them. | ||
| Let's use a PID controller with a basic feedforward. | ||
|
|
||
| :::tabs key:code | ||
| == Kotlin | ||
|
|
||
| ```kotlin | ||
| private val controller = controlSystem { | ||
| velPid(0.005, 0.0, 0.0) | ||
| basicFF(0.0, 0.0, 0.0) | ||
| } | ||
| ``` | ||
|
|
||
| == Java | ||
|
|
||
| ```java | ||
| private ControlSystem controlSystem = ControlSystem.builder() | ||
| .velPid(0.005, 0.0, 0.0) | ||
| .basicFF(0.0, 0.0, 0.0) | ||
| .build(); | ||
| ``` | ||
|
|
||
| ::: | ||
|
|
||
| > [!IMPORTANT] | ||
| > Don't forget to tune your controller! | ||
|
|
||
| Now, we must set our motor power to the `ControlSystem`'s output every loop. We | ||
| can run code every loop by overriding the `periodic()` function. | ||
|
|
||
| The reason we set the motor power in `periodic()` instead of in our commands is | ||
| that the `ControlSystem` needs to be updated every loop to work properly. If we | ||
| only set the motor power in our commands, the motor power would only be updated | ||
| when a command is running, meaning once a command finishes, the motor power | ||
| would stop being updated and thus remain at whatever it was last set to, | ||
| pushing it past its target velocity. | ||
|
|
||
| :::tabs key:code | ||
|
|
||
| == Kotlin | ||
|
|
||
| ```kotlin | ||
| override fun periodic() { | ||
| motor.power = controlSystem.calculate(motor.state) | ||
| } | ||
| ``` | ||
|
|
||
| == Java | ||
|
|
||
| ```java | ||
| @Override | ||
| public void periodic() { | ||
| motor.setPower(controlSystem.calculate(motor.getState())); | ||
| } | ||
| ``` | ||
|
|
||
| ::: | ||
|
|
||
| That's all you need to do to create a motor in NextFTC. | ||
|
|
||
| We're not quite done, though. We still need to create our commands! | ||
|
|
||
| ## Step 3: Create commands | ||
|
|
||
| The last step when you create a Subsystem is to create the commands you'll be | ||
| using. This process varies with each | ||
| subsystem. Here, we'll create two commands. | ||
|
|
||
| To control our motor's velocity , we will be using the `RunToVelocity` command. | ||
|
|
||
| Let's create our first `RunToVelocity` command. | ||
|
|
||
| :::tabs key:code | ||
| == Kotlin | ||
|
|
||
| ```kotlin | ||
| val on: Command = RunToVelocity(controller, 500.0).named("FlywheelOn") | ||
| ``` | ||
|
|
||
| == Java | ||
|
|
||
| ```java | ||
| public final Command on = new RunToVelocity(controller, 500.0) | ||
| .requires(this) | ||
| .named("FlywheelOn"); | ||
| ``` | ||
|
|
||
| ::: | ||
|
|
||
| Pretty easy, right? Let's duplicate it and update our variable name and target | ||
| velocity to create our off command: | ||
|
|
||
| :::tabs key:code | ||
| == Kotlin | ||
|
|
||
| ```kotlin | ||
| val off: Command = RunToVelocity(controller, 0.0).named("FlywheelOff") | ||
| ``` | ||
|
|
||
| == Java | ||
|
|
||
| ```java | ||
| public final Command off = new RunToVelocity(controller, 0.0) | ||
| .requires(this) | ||
| .named("FlywheelOff"); | ||
| ``` | ||
|
|
||
| ::: | ||
|
|
||
| ## Final result | ||
|
|
||
| That's it! You've created your first subsystem! Here is the final result: | ||
|
|
||
| :::tabs key:code | ||
| == Kotlin | ||
|
|
||
| ```kotlin | ||
| object Flywheel : Subsystem { | ||
| private val motor = MotorEx("flywheel_motor") | ||
|
|
||
| private val controller: ControlSystem = controlSystem { | ||
| velPid(0.005, 0.0, 0.0) | ||
| basicFF(0.01, 0.02, 0.03) | ||
| } | ||
|
|
||
| val off: Command = RunToVelocity(controller, 0.0).named("FlywheelOff") | ||
| val on: Command = RunToVelocity(controller, 500.0).named("FlywheelOn") | ||
|
|
||
| override fun periodic() { | ||
| motor.power = controller.calculate(motor.state) | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| == Java | ||
|
|
||
| ```java | ||
| public class Flywheel implements Subsystem { | ||
| public static final Flywheel INSTANCE = new Flywheel(); | ||
| private Flywheel() { } | ||
|
|
||
| private final MotorEx motor = new MotorEx("flywheel_motor"); | ||
|
|
||
| private final ControlSystem controller = ControlSystem.builder() | ||
| .velPid(0.005, 0, 0) | ||
| .basicFF(0.01, 0.02, 0.03) | ||
| .build(); | ||
|
|
||
| public final Command off = new RunToVelocity(controller, 0.0) | ||
| .requires(this) | ||
| .named("FlywheelOff"); | ||
|
|
||
| public final Command on = new RunToVelocity(controller, 500.0) | ||
| .requires(this) | ||
| .named("FlywheelOn"); | ||
|
|
||
| @Override | ||
| public void periodic() { | ||
| motor.setPower(controller.calculate(motor.getState())); | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ::: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In general on this page, it seems to be copy-pasted from the lift page. Since users should have already read that page, it is mostly duplicate information. Instead, in places say "as we did in the lift," or something similar (or at least don't make it the exact same text verbatim, that's boring.)
No description provided.