From 3ffc02ee45e85ef0e1a031ba12d912cf9783b70f Mon Sep 17 00:00:00 2001 From: Daniel1464 Date: Mon, 3 Aug 2026 20:24:00 -0400 Subject: [PATCH 1/3] initial --- .../button/CommandXboxController.java | 4 + .../wpilib/driverstation/XboxController.java | 4 + .../src/main/java/sources/SpotTheError.java | 77 ++++++++++ .../main/java/sources/SpotTheErrorPt2.java | 132 +++++++++++++++++ src/config/sidebarConfig.ts | 8 ++ .../stage1b/command-based-kitbot-pt2.mdx | 2 +- .../stage1b/commands-and-mechanisms-pt2.mdx | 2 +- .../stage1/stage1b/spot-the-error-pt2.mdx | 72 ++++++++++ .../stage1/stage1b/spot-the-error.mdx | 135 ++++++++++++++++++ .../stage1/stage1b/stage-overview.mdx | 2 + 10 files changed, 436 insertions(+), 2 deletions(-) create mode 100644 examples/stage1/stage1b/snippets/src/main/java/sources/SpotTheError.java create mode 100644 examples/stage1/stage1b/snippets/src/main/java/sources/SpotTheErrorPt2.java create mode 100644 src/content/docs/learning-course/stage1/stage1b/spot-the-error-pt2.mdx create mode 100644 src/content/docs/learning-course/stage1/stage1b/spot-the-error.mdx diff --git a/examples/stage1/stage1b/snippets/src/main/java/org/wpilib/command3/button/CommandXboxController.java b/examples/stage1/stage1b/snippets/src/main/java/org/wpilib/command3/button/CommandXboxController.java index 0e6fa243..ac47ce79 100644 --- a/examples/stage1/stage1b/snippets/src/main/java/org/wpilib/command3/button/CommandXboxController.java +++ b/examples/stage1/stage1b/snippets/src/main/java/org/wpilib/command3/button/CommandXboxController.java @@ -18,6 +18,10 @@ public double getLeftY() { return 0; } + public double getRightX() { + return 0; + } + public Trigger a() { return new Trigger(() -> false); } diff --git a/examples/stage1/stage1b/snippets/src/main/java/org/wpilib/driverstation/XboxController.java b/examples/stage1/stage1b/snippets/src/main/java/org/wpilib/driverstation/XboxController.java index ba490e5e..0bb5312b 100644 --- a/examples/stage1/stage1b/snippets/src/main/java/org/wpilib/driverstation/XboxController.java +++ b/examples/stage1/stage1b/snippets/src/main/java/org/wpilib/driverstation/XboxController.java @@ -15,4 +15,8 @@ public XboxController(int id) {} public boolean getAButton() { return false; } + + public boolean getLeftBumper() { + return false; + } } diff --git a/examples/stage1/stage1b/snippets/src/main/java/sources/SpotTheError.java b/examples/stage1/stage1b/snippets/src/main/java/sources/SpotTheError.java new file mode 100644 index 00000000..683a7699 --- /dev/null +++ b/examples/stage1/stage1b/snippets/src/main/java/sources/SpotTheError.java @@ -0,0 +1,77 @@ +/* + * Copyright 2026 FRCSoftware + * + * SPDX-License-Identifier: BSD-3-Clause + */ +package sources; + +import org.wpilib.command3.Command; +import org.wpilib.command3.Mechanism; +import org.wpilib.command3.Trigger; +import org.wpilib.driverstation.XboxController; + +class SpotTheError { + private final XboxController xbox = new XboxController(0); + private final Intake intake = new Intake(); + + void triggerBindings() { + // [triggerCapturedValueBug] + boolean aButton = xbox.getAButton(); + Trigger aButtonTrigger = new Trigger(() -> aButton); + aButtonTrigger.whileTrue(intake.runAtThrottle(0.5)); + // [/triggerCapturedValueBug] + + // [intakeOnTrueBug] + new Trigger(() -> xbox.getLeftBumper()).onTrue(intake.runAtThrottle(0.5)); + // [/intakeOnTrueBug] + + // [intakeWhileTrue] + new Trigger(() -> xbox.getLeftBumper()).whileTrue(intake.runAtThrottle(0.5)); + // [/intakeWhileTrue] + } + + void triggerBindingsFixed() { + // [triggerCapturedValueFix] + Trigger aButtonTrigger = new Trigger(() -> xbox.getAButton()); + aButtonTrigger.whileTrue(intake.runAtThrottle(0.5)); + // [/triggerCapturedValueFix] + } + + // [intakeClass] + class Intake implements Mechanism { + private final ExampleMotor motor = new ExampleMotor(); + + Command runAtThrottle(double throttle) { + return run(coroutine -> { + while (true) { + motor.setThrottle(throttle); + coroutine.yield(); + } + }) + .named("Intake"); + } + } + // [/intakeClass] + + void intakeClassWithDefaultCmd() { + // [intakeClassWithDefaultCmd] + class Intake implements Mechanism { + private final ExampleMotor motor = new ExampleMotor(); + + public Intake() { + setDefaultCommand(runAtThrottle(0)); + } + + Command runAtThrottle(double throttle) { + return run(coroutine -> { + while (true) { + motor.setThrottle(throttle); + coroutine.yield(); + } + }) + .named("Intake"); + } + } + // [/intakeClassWithDefaultCmd] + } +} diff --git a/examples/stage1/stage1b/snippets/src/main/java/sources/SpotTheErrorPt2.java b/examples/stage1/stage1b/snippets/src/main/java/sources/SpotTheErrorPt2.java new file mode 100644 index 00000000..8f10431a --- /dev/null +++ b/examples/stage1/stage1b/snippets/src/main/java/sources/SpotTheErrorPt2.java @@ -0,0 +1,132 @@ +package sources; + +import org.wpilib.command3.Command; +import org.wpilib.command3.Mechanism; +import org.wpilib.command3.Scheduler; +import org.wpilib.command3.button.CommandXboxController; +import org.wpilib.drive.DifferentialDrive; +import org.wpilib.framework.OpModeRobot; +import org.wpilib.hardware.imu.OnboardIMU; + +import java.util.function.DoubleSupplier; + +public class SpotTheErrorPt2 { + private final DifferentialDrive differentialDrive = null; + private final OnboardIMU imu = null; + + class ArcadeDriveBug implements Mechanism { + // [arcadeDriveBug] + Command arcadeDrive(DoubleSupplier forwardThrottle, DoubleSupplier rotationThrottle) { + double forward = forwardThrottle.getAsDouble(); + double rotation = rotationThrottle.getAsDouble(); + return run(coroutine -> { + while (true) { + differentialDrive.arcadeDrive(forward, rotation); + coroutine.yield(); + } + }) + .named("Drive"); + } + // [/arcadeDriveBug] + } + + class ArcadeDriveFix implements Mechanism { + // [arcadeDriveFix] + Command arcadeDrive(DoubleSupplier forwardThrottle, DoubleSupplier rotationThrottle) { + return run(coroutine -> { + while (true) { + differentialDrive.arcadeDrive( + forwardThrottle.getAsDouble(), rotationThrottle.getAsDouble()); + coroutine.yield(); + } + }) + .named("Drive"); + } + // [/arcadeDriveFix] + } + + void swappedSuppliers() { + CommandXboxController xbox = new CommandXboxController(0); + Drivetrain drivetrain = new Drivetrain(); + + // [swappedSuppliersBug] + xbox.a().whileTrue(drivetrain.arcadeDrive(() -> xbox.getRightX(), () -> -xbox.getLeftY())); + // [/swappedSuppliersBug] + + // [swappedSuppliersFix] + xbox.a().whileTrue(drivetrain.arcadeDrive(() -> -xbox.getLeftY(), () -> xbox.getRightX())); + // [/swappedSuppliersFix] + } + + // [robotPeriodicBug] + public class Robot extends OpModeRobot { + private final CommandXboxController xbox = new CommandXboxController(0); + + public Robot() { + xbox.a().whileTrue(printHelloWorld()); + } + + @Override + public void robotPeriodic() {} + + private Command printHelloWorld() { + return Command.noRequirements(coroutine -> { + while (true) { + System.out.println("Hello World!"); + coroutine.yield(); + } + }) + .named("Hello World!"); + } + } + // [/robotPeriodicBug] + + class RobotFixed extends OpModeRobot { + private final Drivetrain drivetrain = new Drivetrain(); + + // [robotPeriodicFix] + @Override + public void robotPeriodic() { + Scheduler.getDefault().run(); + } + // [/robotPeriodicFix] + } + + class RotateInPlaceBug implements Mechanism { + // [rotateInPlaceBug] + Command rotateInPlace(double angleDegrees) { + double targetAngle = imu.getRotation2d().getDegrees() + angleDegrees; + return run(coroutine -> { + while (imu.getRotation2d().getDegrees() < targetAngle) { + differentialDrive.arcadeDrive(0.0, 0.2); + coroutine.yield(); + } + }) + .named("RotateInPlace"); + } + // [/rotateInPlaceBug] + } + + class RotateInPlaceFix implements Mechanism { + // [rotateInPlaceFix] + Command rotateInPlace(double angleDegrees) { + return run(coroutine -> { + double targetAngle = imu.getRotation2d().getDegrees() + angleDegrees; + while (imu.getRotation2d().getDegrees() < targetAngle) { + differentialDrive.arcadeDrive(0.0, 0.2); + coroutine.yield(); + } + }) + .named("RotateInPlace"); + } + // [/rotateInPlaceFix] + } + + class Drivetrain implements Mechanism { + void periodic() {} + + Command arcadeDrive(DoubleSupplier forwardThrottle, DoubleSupplier rotationThrottle) { + return null; + } + } +} diff --git a/src/config/sidebarConfig.ts b/src/config/sidebarConfig.ts index aff81701..c6569f82 100644 --- a/src/config/sidebarConfig.ts +++ b/src/config/sidebarConfig.ts @@ -137,6 +137,10 @@ export const sidebarSections: Record = { label: 'Commands & Mechanisms, Pt. 2', slug: 'learning-course/stage1/stage1b/commands-and-mechanisms-pt2', }, + { + label: 'Bonus: Spot the Error', + slug: 'learning-course/stage1/stage1b/spot-the-error', + }, { label: 'Exercise - Kitbot Rewrite, Pt. 1', slug: 'learning-course/stage1/stage1b/command-based-kitbot', @@ -149,6 +153,10 @@ export const sidebarSections: Record = { label: 'Exercise - Kitbot Rewrite, Pt. 2', slug: 'learning-course/stage1/stage1b/command-based-kitbot-pt2', }, + { + label: 'Bonus: Spot the Error, Pt 2', + slug: 'learning-course/stage1/stage1b/spot-the-error-pt2', + }, ], }, ], diff --git a/src/content/docs/learning-course/stage1/stage1b/command-based-kitbot-pt2.mdx b/src/content/docs/learning-course/stage1/stage1b/command-based-kitbot-pt2.mdx index 00eb2a17..05ee8b1d 100644 --- a/src/content/docs/learning-course/stage1/stage1b/command-based-kitbot-pt2.mdx +++ b/src/content/docs/learning-course/stage1/stage1b/command-based-kitbot-pt2.mdx @@ -2,7 +2,7 @@ title: Exercise - Kitbot Rewrite, Pt. 2 description: Rewriting the kitbot code in stage 1A to command-based prev: learning-course/stage1/stage1b/suppliers-in-command-based -next: false +next: learning-course/stage1/stage1b/spot-the-error-pt2 codeRegionSources: default: stage1/stage1b/snippets/src/main/java/sources/CommandBasedKitbotPt2.java --- diff --git a/src/content/docs/learning-course/stage1/stage1b/commands-and-mechanisms-pt2.mdx b/src/content/docs/learning-course/stage1/stage1b/commands-and-mechanisms-pt2.mdx index 2164d60e..9d88b62f 100644 --- a/src/content/docs/learning-course/stage1/stage1b/commands-and-mechanisms-pt2.mdx +++ b/src/content/docs/learning-course/stage1/stage1b/commands-and-mechanisms-pt2.mdx @@ -2,7 +2,7 @@ title: Commands and Mechanisms, Part 2 description: Intermediate-level uses of commands and mechanisms prev: learning-course/stage1/stage1b/triggers -next: learning-course/stage1/stage1b/command-based-kitbot +next: learning-course/stage1/stage1b/spot-the-error codeRegionSources: default: stage1/stage1b/snippets/src/main/java/sources/CommandsAndMechsPt2.java --- diff --git a/src/content/docs/learning-course/stage1/stage1b/spot-the-error-pt2.mdx b/src/content/docs/learning-course/stage1/stage1b/spot-the-error-pt2.mdx new file mode 100644 index 00000000..dcea6c47 --- /dev/null +++ b/src/content/docs/learning-course/stage1/stage1b/spot-the-error-pt2.mdx @@ -0,0 +1,72 @@ +--- +title: Spot the Error, Part 2 +description: A review exercise for stage 1B +prev: learning-course/stage1/stage1b/command-based-kitbot-pt2 +next: false +codeRegionSources: + default: stage1/stage1b/snippets/src/main/java/sources/SpotTheErrorPt2.java +--- + +### Exercise 1 + +"Hello World!" doesn't show up in the console while the a button is pressed. +Can you spot the error? + +```java #robotPeriodicBug + +``` + +
+ Reveal + The scheduler never runs, so scheduled commands never execute. + Call `Scheduler.getDefault().run()` inside `robotPeriodic()`: + + ```java #robotPeriodicFix + + ``` + +
+ +### Exercise 2 + +This command is supposed to drive the robot using the joystick's forward and rotation axes. + +```java #arcadeDriveBug + +``` + +Can you spot the error? + +
+ Reveal + The supplier values are read once, before the command starts running. + The robot drives at the same speed and rotation forever, even as the joystick moves. + Read the values from the suppliers inside the loop instead: + + ```java #arcadeDriveFix + + ``` + +
+ +### Exercise 3 + +This command is supposed to rotate the robot 90 degrees clockwise from its starting position. + +```java #rotateInPlaceBug + +``` + +Can you spot the error? + +
+ Reveal + The target angle is read once, before the command starts running. + If the robot's heading changes before the command runs, it will rotate to the wrong angle. + Read the target angle from the IMU when the command starts running instead: + + ```java #rotateInPlaceFix + + ``` + +
diff --git a/src/content/docs/learning-course/stage1/stage1b/spot-the-error.mdx b/src/content/docs/learning-course/stage1/stage1b/spot-the-error.mdx new file mode 100644 index 00000000..5d693b41 --- /dev/null +++ b/src/content/docs/learning-course/stage1/stage1b/spot-the-error.mdx @@ -0,0 +1,135 @@ +--- +title: Spot the Error +description: A review exercise for stage 1B +prev: learning-course/stage1/stage1b/commands-and-mechanisms-pt2 +next: learning-course/stage1/stage1b/command-based-kitbot +codeRegionSources: + default: stage1/stage1b/snippets/src/main/java/sources/SpotTheError.java +--- + +import Aside from '@components/Aside.astro'; + +### The Purpose of this Section + +By looking through buggy code snippets that use command-based programming, +you can hopefully get a better intuition on how to spot common bugs and write better code. +If you are confident in your skills, you can skip ahead to the stage 1B exercise, but +the authors still highly recommend it. + + + +### Exercise 1 + +This code is supposed to spin the intake while the left bumper is held. +The intake should stop when the bumper is released. It also compiles fine. + +```java #intakeOnTrueBug + +``` + +Can you spot the error? + +
+ Reveal + The `onTrue()` binding schedules the command once, when the bumper is first pressed. + The command keeps running even after the bumper is released. + Use `whileTrue()` instead, which runs the command for as long as the trigger is active: + + ```java #intakeWhileTrue + + ``` + +
+ +### Exercise 2 + +The `aButtonTrigger` is supposed to run a command while the A button is held. +The code compiles fine. + +```java #triggerCapturedValueBug + +``` + +Can you spot the error? + +
+ Reveal + The button is read once, before the trigger is created. + The trigger always checks the same stored value, so it either runs forever or never runs at all. + Read the button inside the trigger's lambda instead: + + ```java #triggerCapturedValueFix + + ``` + +
+ +### Exercise 3 + +{/* rli:ignore */} + +```java +class Intake implements Mechanism { + private final ExampleMotor motor = new ExampleMotor(); + + Command runAtThrottle(double throttle) { + return Command.noRequirements(coroutine -> { + while (false) { // Compile-time error: Unreachable statement + motor.setThrottle(throttle); + coroutine.yield(); + } + }) + .named("Intake"); + } +} +``` + +Can you fix the compile-time error and the logic error? + +
+ Reveal + The goal is for the commands to set the motor's throttle forever, so + `while (true)` should be used instead of `while (false)`. A + `while (false)` statement will never run! + + Furthermore, the `intake()` Command needs to require the `Intake` mechanism. + So, `run(coroutine -> {})` should be used in place of `Command.noRequirements(coroutine -> {})`. + + ```java #intakeClass + + ``` + +
+ +### Exercise 4 + +You've fixed the intake (reveal the answer to exercise 3 to see the full class), +and have the following code to run it while the A button is held: + +```java #intakeWhileTrue + +``` + +You hold down the A button, and the intake starts spinning; but releasing it doesn't +stop the intake. Can you spot the error? + +
+ Hint + Setting the Intake's default command might help you. But why? +
+
+ Reveal + When you call `motor.setThrottle(double)`, the motor will start spinning forever, + even if you aren't calling `setThrottle` anymore. Even though releasing the A button + will cancel the `runAtThrottle` command, it won't stop the motor. + + To fix this, we set a default command. The default command for a mechanism will always + run when no other commands are requiring that mechanism. In this case, "no other + command to the intake" = "we want to stop the intake", so the default command is + setting the throttle to 0. + ```java #intakeClassWithDefaultCmd + + ``` +
\ No newline at end of file diff --git a/src/content/docs/learning-course/stage1/stage1b/stage-overview.mdx b/src/content/docs/learning-course/stage1/stage1b/stage-overview.mdx index 7ceb62d0..dfb61756 100644 --- a/src/content/docs/learning-course/stage1/stage1b/stage-overview.mdx +++ b/src/content/docs/learning-course/stage1/stage1b/stage-overview.mdx @@ -24,6 +24,8 @@ This stage will cover the following topics: - [Commands & Mechanisms, Part 1](https://frcsoftware.org/learning-course/stage1/stage1b/commands-and-mechanisms/) - [Triggers and Scheduling](https://frcsoftware.org/learning-course/stage1/stage1b/triggers/) - [Commands and Mechanisms, Part 2](https://frcsoftware.org/learning-course/stage1/stage1b/commands-and-mechanisms-pt2/) +- [Bonus: Spot the Error](https://frcsoftware.org/learning-course/stage1/stage1b/spot-the-error/) - [Exercise: Kitbot Rewrite, Pt 1](https://frcsoftware.org/learning-course/stage1/stage1b/command-based-kitbot/) - [Suppliers in Command-Based](https://frcsoftware.org/learning-course/stage1/stage1b/suppliers-in-command-based/) - [Exercise: Kitbot Rewrite, Pt 2](https://frcsoftware.org/learning-course/stage1/stage1b/command-based-kitbot-pt2/) +- [Bonus: Spot the Error, Pt 2](https://frcsoftware.org/learning-course/stage1/stage1b/spot-the-error-pt2/) From 47a571f2f12144ca3ce76fb59e080980bbac4fbc Mon Sep 17 00:00:00 2001 From: Daniel1464 Date: Mon, 3 Aug 2026 21:00:21 -0400 Subject: [PATCH 2/3] lint --- .../src/main/java/sources/SpotTheError.java | 24 +++--- .../main/java/sources/SpotTheErrorPt2.java | 85 +++++++++---------- .../stage1/stage1b/spot-the-error.mdx | 12 ++- 3 files changed, 58 insertions(+), 63 deletions(-) diff --git a/examples/stage1/stage1b/snippets/src/main/java/sources/SpotTheError.java b/examples/stage1/stage1b/snippets/src/main/java/sources/SpotTheError.java index 683a7699..ce1b5663 100644 --- a/examples/stage1/stage1b/snippets/src/main/java/sources/SpotTheError.java +++ b/examples/stage1/stage1b/snippets/src/main/java/sources/SpotTheError.java @@ -43,12 +43,12 @@ class Intake implements Mechanism { Command runAtThrottle(double throttle) { return run(coroutine -> { - while (true) { - motor.setThrottle(throttle); - coroutine.yield(); - } - }) - .named("Intake"); + while (true) { + motor.setThrottle(throttle); + coroutine.yield(); + } + }) + .named("Intake"); } } // [/intakeClass] @@ -64,12 +64,12 @@ public Intake() { Command runAtThrottle(double throttle) { return run(coroutine -> { - while (true) { - motor.setThrottle(throttle); - coroutine.yield(); - } - }) - .named("Intake"); + while (true) { + motor.setThrottle(throttle); + coroutine.yield(); + } + }) + .named("Intake"); } } // [/intakeClassWithDefaultCmd] diff --git a/examples/stage1/stage1b/snippets/src/main/java/sources/SpotTheErrorPt2.java b/examples/stage1/stage1b/snippets/src/main/java/sources/SpotTheErrorPt2.java index 8f10431a..7ed0dca9 100644 --- a/examples/stage1/stage1b/snippets/src/main/java/sources/SpotTheErrorPt2.java +++ b/examples/stage1/stage1b/snippets/src/main/java/sources/SpotTheErrorPt2.java @@ -1,5 +1,11 @@ +/* + * Copyright 2026 FRCSoftware + * + * SPDX-License-Identifier: BSD-3-Clause + */ package sources; +import java.util.function.DoubleSupplier; import org.wpilib.command3.Command; import org.wpilib.command3.Mechanism; import org.wpilib.command3.Scheduler; @@ -8,8 +14,6 @@ import org.wpilib.framework.OpModeRobot; import org.wpilib.hardware.imu.OnboardIMU; -import java.util.function.DoubleSupplier; - public class SpotTheErrorPt2 { private final DifferentialDrive differentialDrive = null; private final OnboardIMU imu = null; @@ -20,12 +24,12 @@ Command arcadeDrive(DoubleSupplier forwardThrottle, DoubleSupplier rotationThrot double forward = forwardThrottle.getAsDouble(); double rotation = rotationThrottle.getAsDouble(); return run(coroutine -> { - while (true) { - differentialDrive.arcadeDrive(forward, rotation); - coroutine.yield(); - } - }) - .named("Drive"); + while (true) { + differentialDrive.arcadeDrive(forward, rotation); + coroutine.yield(); + } + }) + .named("Drive"); } // [/arcadeDriveBug] } @@ -34,30 +38,17 @@ class ArcadeDriveFix implements Mechanism { // [arcadeDriveFix] Command arcadeDrive(DoubleSupplier forwardThrottle, DoubleSupplier rotationThrottle) { return run(coroutine -> { - while (true) { - differentialDrive.arcadeDrive( - forwardThrottle.getAsDouble(), rotationThrottle.getAsDouble()); - coroutine.yield(); - } - }) - .named("Drive"); + while (true) { + differentialDrive.arcadeDrive( + forwardThrottle.getAsDouble(), rotationThrottle.getAsDouble()); + coroutine.yield(); + } + }) + .named("Drive"); } // [/arcadeDriveFix] } - void swappedSuppliers() { - CommandXboxController xbox = new CommandXboxController(0); - Drivetrain drivetrain = new Drivetrain(); - - // [swappedSuppliersBug] - xbox.a().whileTrue(drivetrain.arcadeDrive(() -> xbox.getRightX(), () -> -xbox.getLeftY())); - // [/swappedSuppliersBug] - - // [swappedSuppliersFix] - xbox.a().whileTrue(drivetrain.arcadeDrive(() -> -xbox.getLeftY(), () -> xbox.getRightX())); - // [/swappedSuppliersFix] - } - // [robotPeriodicBug] public class Robot extends OpModeRobot { private final CommandXboxController xbox = new CommandXboxController(0); @@ -71,12 +62,12 @@ public void robotPeriodic() {} private Command printHelloWorld() { return Command.noRequirements(coroutine -> { - while (true) { - System.out.println("Hello World!"); - coroutine.yield(); - } - }) - .named("Hello World!"); + while (true) { + System.out.println("Hello World!"); + coroutine.yield(); + } + }) + .named("Hello World!"); } } // [/robotPeriodicBug] @@ -97,12 +88,12 @@ class RotateInPlaceBug implements Mechanism { Command rotateInPlace(double angleDegrees) { double targetAngle = imu.getRotation2d().getDegrees() + angleDegrees; return run(coroutine -> { - while (imu.getRotation2d().getDegrees() < targetAngle) { - differentialDrive.arcadeDrive(0.0, 0.2); - coroutine.yield(); - } - }) - .named("RotateInPlace"); + while (imu.getRotation2d().getDegrees() < targetAngle) { + differentialDrive.arcadeDrive(0.0, 0.2); + coroutine.yield(); + } + }) + .named("RotateInPlace"); } // [/rotateInPlaceBug] } @@ -111,13 +102,13 @@ class RotateInPlaceFix implements Mechanism { // [rotateInPlaceFix] Command rotateInPlace(double angleDegrees) { return run(coroutine -> { - double targetAngle = imu.getRotation2d().getDegrees() + angleDegrees; - while (imu.getRotation2d().getDegrees() < targetAngle) { - differentialDrive.arcadeDrive(0.0, 0.2); - coroutine.yield(); - } - }) - .named("RotateInPlace"); + double targetAngle = imu.getRotation2d().getDegrees() + angleDegrees; + while (imu.getRotation2d().getDegrees() < targetAngle) { + differentialDrive.arcadeDrive(0.0, 0.2); + coroutine.yield(); + } + }) + .named("RotateInPlace"); } // [/rotateInPlaceFix] } diff --git a/src/content/docs/learning-course/stage1/stage1b/spot-the-error.mdx b/src/content/docs/learning-course/stage1/stage1b/spot-the-error.mdx index 5d693b41..cfd55aa2 100644 --- a/src/content/docs/learning-course/stage1/stage1b/spot-the-error.mdx +++ b/src/content/docs/learning-course/stage1/stage1b/spot-the-error.mdx @@ -17,13 +17,15 @@ If you are confident in your skills, you can skip ahead to the stage 1B exercise the authors still highly recommend it. ### Exercise 1 This code is supposed to spin the intake while the left bumper is held. -The intake should stop when the bumper is released. It also compiles fine. +The intake should stop when the bumper is released. +It also compiles fine. ```java #intakeOnTrueBug @@ -113,7 +115,8 @@ and have the following code to run it while the A button is held: ``` You hold down the A button, and the intake starts spinning; but releasing it doesn't -stop the intake. Can you spot the error? +stop the intake. +Can you spot the error?
Hint @@ -132,4 +135,5 @@ stop the intake. Can you spot the error? ```java #intakeClassWithDefaultCmd ``` -
\ No newline at end of file + + From 7f9981f055146f0a4c89aad105d4f6005d17691e Mon Sep 17 00:00:00 2001 From: Daniel1464 Date: Mon, 3 Aug 2026 21:12:29 -0400 Subject: [PATCH 3/3] Swap to relative URLs to pass CI --- .../stage1/stage1b/stage-overview.mdx | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/content/docs/learning-course/stage1/stage1b/stage-overview.mdx b/src/content/docs/learning-course/stage1/stage1b/stage-overview.mdx index dfb61756..18b35719 100644 --- a/src/content/docs/learning-course/stage1/stage1b/stage-overview.mdx +++ b/src/content/docs/learning-course/stage1/stage1b/stage-overview.mdx @@ -19,13 +19,13 @@ By the end of Stage 1B, you'll rewrite your Stage 1A kitbot code into a command- This stage will cover the following topics: -- [The Concepts of Command-Based Programming](https://frcsoftware.org/learning-course/stage1/stage1b/command-based-overview/) -- [The Body of a Command](https://frcsoftware.org/learning-course/stage1/stage1b/the-command-body/) -- [Commands & Mechanisms, Part 1](https://frcsoftware.org/learning-course/stage1/stage1b/commands-and-mechanisms/) -- [Triggers and Scheduling](https://frcsoftware.org/learning-course/stage1/stage1b/triggers/) -- [Commands and Mechanisms, Part 2](https://frcsoftware.org/learning-course/stage1/stage1b/commands-and-mechanisms-pt2/) -- [Bonus: Spot the Error](https://frcsoftware.org/learning-course/stage1/stage1b/spot-the-error/) -- [Exercise: Kitbot Rewrite, Pt 1](https://frcsoftware.org/learning-course/stage1/stage1b/command-based-kitbot/) -- [Suppliers in Command-Based](https://frcsoftware.org/learning-course/stage1/stage1b/suppliers-in-command-based/) -- [Exercise: Kitbot Rewrite, Pt 2](https://frcsoftware.org/learning-course/stage1/stage1b/command-based-kitbot-pt2/) -- [Bonus: Spot the Error, Pt 2](https://frcsoftware.org/learning-course/stage1/stage1b/spot-the-error-pt2/) +- [The Concepts of Command-Based Programming](/learning-course/stage1/stage1b/command-based-overview/) +- [The Body of a Command](/learning-course/stage1/stage1b/the-command-body/) +- [Commands & Mechanisms, Part 1](/learning-course/stage1/stage1b/commands-and-mechanisms/) +- [Triggers and Scheduling](/learning-course/stage1/stage1b/triggers/) +- [Commands and Mechanisms, Part 2](/learning-course/stage1/stage1b/commands-and-mechanisms-pt2/) +- [Bonus: Spot the Error](/learning-course/stage1/stage1b/spot-the-error/) +- [Exercise: Kitbot Rewrite, Pt 1](/learning-course/stage1/stage1b/command-based-kitbot/) +- [Suppliers in Command-Based](/learning-course/stage1/stage1b/suppliers-in-command-based/) +- [Exercise: Kitbot Rewrite, Pt 2](/learning-course/stage1/stage1b/command-based-kitbot-pt2/) +- [Bonus: Spot the Error, Pt 2](/learning-course/stage1/stage1b/spot-the-error-pt2/)