Skip to content

Commit 2b163c7

Browse files
committed
Updated driving_robot to use command factories.
1 parent bd3e242 commit 2b163c7

3 files changed

Lines changed: 32 additions & 230 deletions

File tree

.claude/settings.local.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010
"Bash(python3 -m mkdocs build)",
1111
"Bash(pip3 install:*)",
1212
"Bash(git mv:*)",
13-
"Bash(python3.14 -m mkdocs build)"
13+
"Bash(python3.14 -m mkdocs build)",
14+
"Bash(mkdocs build:*)"
1415
]
1516
}
1617
}

docs/code_examples/2026KitBotInline/commands/DriveArcadeCommand.java

Lines changed: 0 additions & 70 deletions
This file was deleted.

docs/programming/driving_robot.md

Lines changed: 30 additions & 159 deletions
Original file line numberDiff line numberDiff line change
@@ -230,191 +230,62 @@ Then in the constructor, configure the followers to follow the leaders:
230230
??? example "Full Drive Subsystem Example"
231231
See [CANDriveSubsystem.java](../code_examples/2026KitBotInline/subsystems/CANDriveSubsystem.java) for the complete implementation with all motor configuration and initialization.
232232

233-
### Creating the arcadeDrive method
233+
### Creating the driveArcade Command Factory
234234

235-
Now it’s time to make an arcadeDrive from our differentialDrive!
235+
Instead of writing a separate command class, we use the **command factory pattern** — a method on the subsystem that returns a `Command`. This is the modern WPILib approach and keeps drive logic inside `CANDriveSubsystem` where it belongs. See [Command Based Robot](../basics/wpilib.md#command-based-robot){target=_blank} for background on commands.
236236

237237
!!! abstract
238-
**1)** Let’s create a public void method called “arcadeDrive” with type “double” parameters moveSpeed and rotateSpeed.
238+
Below the `periodic` method, add the `driveArcade` factory method:
239239

240-
Below the `periodic` method create a new method called `arcadeDrive`. This method will be called from our Drive command to actually move the robot.
241-
242-
```java
243-
public void arcadeDrive(double moveSpeed, double rotateSpeed) {
244-
245-
}
246-
```
247-
248-
!!! tip
249-
By putting something in the parentheses it makes the method require a parameter when it is used. When the method gets used and parameters are passed, they will be store in moveSpeed and rotateSpeed (in that order). See [parameters](../basics/java_basics.md#parameters){target=_blank} for more info.
250-
251-
!!! abstract
252-
**2)** Now lets make our method call the differentialDrive’s arcadeDrive method.
253-
254-
Inside our method type the call to the differential drive:
255-
256-
```java
240+
```java title=”CANDriveSubsystem.java”
257241
--8<-- “docs/code_examples/2026KitBotInline/subsystems/CANDriveSubsystem.java:drive-arcade-method”
258242
```
259243

260-
DifferentialDrive’s arcadeDrive method takes parameters moveValue and rotateValue.
244+
- `this.run(...)` creates a command that calls the lambda repeatedly while scheduled. The subsystem is automatically added as a requirement.
245+
- The parameters are `DoubleSupplier` (a function that returns a `double`) rather than plain `double` values. This ensures the joystick reading is evaluated every loop cycle instead of being captured once. this is important to ensure the robot continuously responds to joystick movement.
246+
- `drive.arcadeDrive(...)` is the WPILib `DifferentialDrive` call that physically moves the motors.
261247

262248
!!! note
263-
At this point you could instead create a tank drive, however implementation differs slightly.
264-
To do so type `differentialDrive.tankDrive(moveSpeed, rotateSpeed);` instead of `differentialDrive.arcadeDrive(moveSpeed, rotateSpeed);` and change the method name reflect this.
249+
To use tank drive instead, replace `drive.arcadeDrive(...)` with `drive.tankDrive(...)` and rename the method accordingly.
265250

266251
!!! tip
267-
If you want to limit the max speed you can multiple the speeds by a decimal (i.e. 0.5*moveSpeed will make the motors only move half of their maximum speed)
268-
269-
You may want to do this for initial testing to make sure everything is going the right direction.
270-
271-
### Making our robot controllable
252+
Multiply the speed values by a decimal to cap the max speed during initial testing (e.g. `xSpeed.getAsDouble() * 0.5`). This makes it easier to verify the robot drives in the correct directions before running at full power/speed.
272253

273-
## Creating the Drivearcade Command
254+
## Wiring Up in RobotContainer
274255

275-
- Remember that **methods** tell the robot what it can do but in order to make it do these things we must give it a **command**. See [Command Based Robot](../basics/wpilib.md#command-based-robot){target=_blank}
276-
- Now that we have created the method, we need to create a command to call and use that method.
277-
- Let’s create a new command called **DriveArcade** that calls arcadeDrive method we just created!
256+
Now we connect the subsystem to the driver’s controller by setting a default command in `RobotContainer.java`.
278257

279-
Before we begin we must create the class file for the DriveArcade command. See [Creating a New Command](new_project.md#creating-a-new-command){target=_blank} for info on how to do this and info on what each pre-created method does.
258+
### Adding the Driver Controller
280259

281-
### Define variables
282-
283-
!!! note
284-
**1)** Create `xspeed` and `zrotation` variables. (to be passed to drive subsystem). These will be declared as `DoubleSuppliers`, which is a function that return a type. This is important for later.
285-
**2)** Create an emtpy `driveSubsystem` instance of `Drivetrain`
286-
287-
!!! warning
288-
`DoubleSupplier` and `Drivetrain` will have to be imported as follows:
289-
```Java
290-
import frc.robot.subsystems.CANDriveSubsystem;
291-
import java.util.function.DoubleSupplier;
292-
```
293-
294-
```java title=”DriveArcadeCommand.java”
295-
--8<-- “docs/code_examples/2026KitBotInline/commands/DriveArcadeCommand.java:class-variables”
296-
```
297-
298-
### In the constructor
260+
The `RobotContainer` class holds all subsystems, controllers, and command bindings. A `CommandXboxController` is declared here and reads joystick input.
299261

300262
!!! note
301-
**1)** Inside the parenthesis of the constructor `driveArcade()` add 3 variables:
302-
```java title=”DriveArcadeCommand.java”
303-
--8<-- “docs/code_examples/2026KitBotInline/commands/DriveArcadeCommand.java:constructor-signature
304-
```
305-
These are values that will be passed into the command in `RobotContainer.java`
306-
307-
!!! note
308-
**2)** Inside constructor implementation type:
309-
310-
```java title=”DriveArcadeCommand.java”
311-
--8<-- “docs/code_examples/2026KitBotInline/commands/DriveArcadeCommand.java:constructor-body”
312-
```
263+
**1)** Open `Constants.java` and confirm the `DRIVER_CONTROLLER_PORT` constant is present inside `OperatorConstants`.
313264

314-
- The lines starting with `this` set the global variables we defined at the top of our class file to the values being passed into the consturctor.
315-
!!! tip
316-
`this` is how the class instance `object` refers to itself in code.
317-
318-
!!! note “”
319-
- `addRequirements` means this command will end all other commands currently using drivetrain and will run instead when executed.
320-
- It also means, other commands that require drivetrain will stop this command and run instead when executed.
321-
322-
!!! warning
323-
If you use the light bulb to import ‘Robot’, be sure to import the one with “frc.robot”
324-
325-
### In the execute method
265+
**2)** Open `RobotContainer.java` and confirm a `CommandXboxController driverController` field is declared at the top of the class that uses that constant.
326266

327-
!!! note
328-
**1)** In the execute method we will we want to call the **arcadeDrive** method we created in **Drivetrain** and give it the variables **moveSpeed** `xspeed` and **rotateSpeed** `zrotation` we created as parameters.
329-
330-
```java title=”DriveArcadeCommand.java”
331-
--8<-- “docs/code_examples/2026KitBotInline/commands/DriveArcadeCommand.java:execute-method”
332-
```
267+
!!! tip “Finding your joystick port in the Driver Station”
268+
Open the **Driver Station** application and click the **USB** tab (the plug icon on the left). The number next to your controller is its port — use that value for `DRIVER_CONTROLLER_PORT` in Constants. Controllers can be dragged in the list to change their assigned port (the controller port is usually 0 by default if only one controller is plugged in).
333269

334-
### In the isFinished method
335-
336-
Since we will be using this command to control the robot we want it to run indefinitely.
337-
338-
!!! note
339-
**1)** To do this we are going to continue having isFinished return false, meaning the command will never finish.
340-
341-
```java title=”DriveArcadeCommand.java”
342-
--8<-- “docs/code_examples/2026KitBotInline/commands/DriveArcadeCommand.java:is-finished-method”
343-
```
344-
345-
!!! tip
346-
- If we did want a command to finish, we make this return true.
347-
- This can be done by replacing false with true to make it finish instantly
348-
- Alternatively we can make a condition which can return true
349-
- For example `(timePassed > 10)` will return true after 10 seconds but return false anytime before 10 seconds have passed.
270+
### Using setDefaultCommand
350271

351-
### In the end method
272+
`setDefaultCommand` tells a subsystem which command to run whenever no other command is using it. Since we always want the driver to be able to move the robot, the drive factory command is set as the default.
352273

353-
!!! note
354-
**1)** We will call the arcadeDrive method and give it 0 and 0 as the parameters. this will stop the robot when the command completes.
274+
!!! abstract
275+
Inside `configureBindings()` in `RobotContainer.java`, add:
355276

356-
```java title=”DriveArcadeCommand.java”
357-
--8<-- “docs/code_examples/2026KitBotInline/commands/DriveArcadeCommand.java:end-method
277+
```java title=”RobotContainer.java”
278+
--8<-- “docs/code_examples/2026KitBotInline/RobotContainer.java:drive-config
358279
```
359280

360-
- This make the motors stop running when the command ends by setting the movement speed to zero and rotation speed to zero.
361-
362-
### Completed Example
363-
364-
See [DriveArcadeCommand.java](../code_examples/2026KitBotInline/commands/DriveArcadeCommand.java) for the complete command class implementation.
365-
366-
### Creating the Joystick
367-
368-
In order to drive our robot, it needs to know what will be controlling it. To do so, we will use the joystick in `RobotContainer.java`, as `m_drivecontroller`.
369-
370-
!!! note
371-
**1)** Open Constants.java
372-
Check and make sure the `kDriverControllerPort` constant is present.
373-
**2)** Open RobotContainer.java
374-
- in the imports section, change `ExampleCommand` to `DriveArcade`.
375-
- inside the class, find the line ` private final ExampleSubsystem m_exampleSubsystem = new ExampleSubsystem();` and change `ExampleSubsystem` to `Drivetrain` and `m_exampleSubsystem` to `drivetrain`.
281+
- The Y axis is negated so pushing the stick away from you (a negative joystick value) drives the robot forward (positive motor output).
282+
- The X axis is negated to match WPILib’s counter-clockwise-positive rotation convention.
283+
- Both axes are scaled by constants defined in `OperatorConstants` to make the robot easier to control at full stick deflection.
376284

377-
!!! tip "Finding your joystick port in the Driver Station"
378-
If you are not sure which port your controller is on, open the **Driver Station** application, click the **USB** tab (the icon that looks like a USB plug on the left side), and look at the numbered list of connected devices. The number next to your controller is the port you should use for `kDriverControllerPort` in Constants. Devices can be dragged up or down in the list to change their assigned port number.
379-
380-
### Using setDefaultCommand
381-
382-
!!! note
383-
**1)** Back in **RobotContainer.java** We will need to remove everything inside the `configureBindings` method.
384-
**2)** in the `configureBindings`we will call the `setDefaultCommand` of `drivetrain` and create a new `DriveArcade` command with parameters.
385-
386-
!!! tip
387-
- Commands in this method will run when the robot is enabled.
388-
- They also run if no other commands using the subsystem are running.
389-
- This is why we write **addRequirements(Robot.subsystemName)** in the commands we create, it ends currently running commands using that subsystem to allow a new command is run.
390-
- We will the default command for the drive subsystem to an instance of the `DriveArcade` with the values provided by the joystick axes on the driver controller.
391-
- The Y axis of the controller is inverted so that pushing the stick away from you (a negative value) drives the robot forwards (a positive value).
392-
- Similarly for the X axis where we need to flip the value so the joystick matches the WPILib convention of counter-clockwise positive
393-
394-
```java title="RobotContainer.java"
395-
--8<-- "docs/code_examples/2026KitBotInline/RobotContainer.java:drive-config"
396-
```
397285
!!! tip
398-
- Notice the `()->` notation above. This notation creates lamdas or anonymous methods. [More about Lambdas](https://www.w3schools.com/java/java_lambda.asp){target=_blank}
399-
- The lambas are required because we set the parameter types of `xpeed` and 'zrotation' in our `DriveArcade` to be `DoubleSuppliers`, which are methods that return doubles. (Which is what the lambdas above return.)
400-
- These are declared as such so that they get and send the updated values from `m_driverController.getLeftY()` and `m_driverController.getRightX()` to the drive motors continuously.
401-
402-
!!! tip
403-
Remember to use the light bulb for importing if needed!
404-
!!! tip
405-
The `New` keyword creates a new instance of a class (object)
406-
407-
??? example "Full RobotContainer Example"
408-
See [RobotContainer.java](../code_examples/2026KitBotInline/RobotContainer.java) for the complete RobotContainer implementation.
409-
410-
The key part for drive configuration is in `configureBindings()`:
411-
412-
```java title="RobotContainer.java"
413-
--8<-- "docs/code_examples/2026KitBotInline/RobotContainer.java:drive-config"
414-
```
286+
The `()->` syntax creates a **lambda** — an anonymous function. [More about Lambdas](https://www.w3schools.com/java/java_lambda.asp){target=_blank}
415287

416-
This sets arcade drive as the default command, using:
288+
Lambdas are required here because `driveArcade` expects `DoubleSupplier` parameters. A lambda `() -> driverController.getLeftY()` is a `DoubleSupplier` — it gets called every loop cycle so the robot continuously responds to joystick movement.
417289

418-
- The negative Y-axis of the left joystick (inverted so pushing away drives forward)
419-
- The negative X-axis of the right joystick (inverted for WPILib counter-clockwise positive convention)
420-
- Both axes scaled for controllability
290+
??? example “Full RobotContainer Example”
291+
See [RobotContainer.java](../code_examples/2026KitBotInline/RobotContainer.java) for the complete `RobotContainer` implementation.

0 commit comments

Comments
 (0)