Skip to content

Conversation

@sciencewhiz
Copy link
Collaborator

  • Replace deprecated feedforward.calculate(velocity, acceleration)

Update ProfiledPIDController documentation to use the recommended feedforward.calculate(currentVelocity, nextVelocity) overload instead of the deprecated (velocity, acceleration) version.

This eliminates manual acceleration calculations and uses the newer API that calculates acceleration internally from velocity change.

Fixes #2963

  • Convert ProfiledPIDController feedforward example to use snippets

Replace inline code blocks with RLIs to snippets from allwpilib. Java and C++ examples now reference compilable snippet code that will be tested in every allwpilib build.

Python remains as inline code block since Python snippets are maintained in robotpy repository.

Related: wpilibsuite/allwpilib#8280

  • Manually update RLI

…libsuite#3117)

* Replace deprecated feedforward.calculate(velocity, acceleration)

Update ProfiledPIDController documentation to use the recommended
feedforward.calculate(currentVelocity, nextVelocity) overload instead
of the deprecated (velocity, acceleration) version.

This eliminates manual acceleration calculations and uses the newer
API that calculates acceleration internally from velocity change.

Fixes wpilibsuite#2963

* Convert ProfiledPIDController feedforward example to use snippets

Replace inline code blocks with RLIs to snippets from allwpilib.
Java and C++ examples now reference compilable snippet code that
will be tested in every allwpilib build.

Python remains as inline code block since Python snippets are
maintained in robotpy repository.

Related: wpilibsuite/allwpilib#8280

* Manually update RLI

---------

Co-authored-by: sciencewhiz <[email protected]>
@github-actions github-actions bot added the 2027 label Nov 20, 2025
@sciencewhiz
Copy link
Collaborator Author

\inspector fix all

@github-actions
Copy link
Contributor

Inspector Report


Up To Date

ALL @ <source/docs/contributing/frc-docs/style-guide.rst>
ALL @ <source/docs/romi-robot/programming-romi.rst>
ALL @ <source/docs/software/advanced-controls/controllers/trapezoidal-profiles.rst>
ALL @ <source/docs/software/advanced-controls/state-space/state-space-flywheel-walkthrough.rst>
ALL @ <source/docs/software/advanced-controls/state-space/state-space-observers.rst>
ALL @ <source/docs/software/advanced-gradlerio/code-formatting.rst>
ALL @ <source/docs/software/advanced-gradlerio/profiling-with-visualvm.rst>
ALL @ <source/docs/software/basic-programming/deploy-directory.rst>
ALL @ <source/docs/software/basic-programming/java-gc.rst>
ALL @ <source/docs/software/basic-programming/robot-preferences.rst>
ALL @ <source/docs/software/can-devices/power-distribution-module.rst>
ALL @ <source/docs/software/commandbased/commands-v2/binding-commands-to-triggers.rst>
ALL @ <source/docs/software/commandbased/commands-v2/command-compositions.rst>
ALL @ <source/docs/software/commandbased/commands-v2/commands.rst>
ALL @ <source/docs/software/commandbased/commands-v2/cpp-command-discussion.rst>
ALL @ <source/docs/software/commandbased/commands-v2/pid-subsystems-commands.rst>
ALL @ <source/docs/software/commandbased/commands-v2/profile-subsystems-commands.rst>
ALL @ <source/docs/software/commandbased/commands-v2/profilepid-subsystems-commands.rst>
ALL @ <source/docs/software/commandbased/commands-v2/structuring-command-based-project.rst>
ALL @ <source/docs/software/dashboards/glass/mech2d-widget.rst>
ALL @ <source/docs/software/hardware-apis/sensors/analog-inputs-software.rst>
ALL @ <source/docs/software/hardware-apis/sensors/analog-potentiometers-software.rst>
ALL @ <source/docs/software/hardware-apis/sensors/digital-inputs-software.rst>
ALL @ <source/docs/software/hardware-apis/sensors/limit-switch.rst>
ALL @ <source/docs/software/vision-processing/roborio/using-the-cameraserver-on-the-roborio.rst>
ALL @ <source/docs/software/vscode-overview/creating-robot-program.rst>
ALL @ <source/docs/software/wpilib-tools/robot-simulation/physics-sim.rst>
ALL @ <source/docs/software/wpilib-tools/robot-simulation/unit-testing.rst>
ALL @ <source/docs/xrp-robot/programming-xrp.rst>
ALL @ <source/docs/zero-to-robot/step-4/creating-test-drivetrain-program-cpp-java-python.rst>
wpilibjExamples/src/main/java/edu/wpi/first/wpilibj/examples/elevatorprofiledpid/Robot.java#L5-EOF @ <source/docs/software/advanced-controls/controllers/profiled-pidcontroller.rst:119>
wpilibcExamples/src/main/cpp/examples/ElevatorProfiledPID/cpp/Robot.cpp#L5-EOF @ <source/docs/software/advanced-controls/controllers/profiled-pidcontroller.rst:124>
ElevatorProfiledPID/robot.py#L8-EOF @ <source/docs/software/advanced-controls/controllers/profiled-pidcontroller.rst:129>

Outdated - Automatically Fixed

wpilibjExamples/src/main/java/edu/wpi/first/wpilibj/templates/commandbased/subsystems/ExampleSubsystem.java#L7-EOF @ <source/docs/software/commandbased/commands-v2/subsystems.rst:18>
wpilibcExamples/src/main/cpp/templates/commandbased/include/subsystems/ExampleSubsystem.h#L5-EOF @ <source/docs/software/commandbased/commands-v2/subsystems.rst:26>
wpilibcExamples/src/main/cpp/examples/HatchbotTraditional/include/subsystems/HatchSubsystem.h#L5-EOF @ <source/docs/software/commandbased/commands-v2/subsystems.rst:85>
wpilibcExamples/src/main/cpp/examples/HatchbotInlined/include/subsystems/HatchSubsystem.h#L5-EOF @ <source/docs/software/commandbased/commands-v2/subsystems.rst:123>

Invalid - Manual Intervention Needed

v2027.0.0-alpha-2 | v2026.1.1-beta-1/wpilibjExamples/src/main/java/edu/wpi/first/wpilibj/snippets/profiledpidfeedforward/Robot.java#L37-L44 @ <source/docs/software/advanced-controls/controllers/profiled-pidcontroller.rst:87>

-	37	 	  public void goToPosition(double goalPosition) {
-	38	 	    double pidVal = m_controller.calculate(m_encoder.getDistance(), goalPosition);
-	39	 	    m_motor.setVoltage(
-	40	 	        pidVal
-	41	 	            + m_feedforward.calculateWithVelocities(
-	42	 	                m_lastSpeed, m_controller.getSetpoint().velocity));
-	43	 	    m_lastSpeed = m_controller.getSetpoint().velocity;
-	44	 	  }
+	 	37	

v2027.0.0-alpha-2 | v2026.1.1-beta-1/wpilibcExamples/src/main/cpp/snippets/ProfiledPIDFeedforward/cpp/Robot.cpp#L25-L32 @ <source/docs/software/advanced-controls/controllers/profiled-pidcontroller.rst:92>

-	25	 	  void GoToPosition(units::meter_t goalPosition) {
-	26	 	    auto pidVal = m_controller.Calculate(
-	27	 	        units::meter_t{m_encoder.GetDistance()}, goalPosition);
-	28	 	    m_motor.SetVoltage(units::volt_t{pidVal} +
-	29	 	                       m_feedforward.Calculate(
-	30	 	                           m_lastSpeed, m_controller.GetSetpoint().velocity));
-	31	 	    m_lastSpeed = m_controller.GetSetpoint().velocity;
-	32	 	  }
+	 	25	

v2027.0.0-alpha-2 | v2023.4.3/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/CommandScheduler.java#L202-L245 @ <source/docs/software/commandbased/commands-v2/command-scheduler.rst:34>

-	202	 	  private void schedule(Command command) {
-	203	 	    if (command == null) {
-	204	 	      DriverStation.reportWarning("Tried to schedule a null command", true);
-	205	 	      return;
-	206	 	    }
-	207	 	    if (m_inRunLoop) {
-	208	 	      m_toSchedule.add(command);
-	209	 	      return;
-	210	 	    }
-	211	 	
-	212	 	    requireNotComposed(command);
-	213	 	
-	214	 	    // Do nothing if the scheduler is disabled, the robot is disabled and the command doesn't
-	215	 	    // run when disabled, or the command is already scheduled.
-	216	 	    if (m_disabled
-	217	 	        || isScheduled(command)
-	218	 	        || RobotState.isDisabled() && !command.runsWhenDisabled()) {
-	219	 	      return;
-	220	 	    }
-	221	 	
-	222	 	    Set<Subsystem> requirements = command.getRequirements();
-	223	 	
-	224	 	    // Schedule the command if the requirements are not currently in-use.
-	225	 	    if (Collections.disjoint(m_requirements.keySet(), requirements)) {
-	226	 	      initCommand(command, requirements);
 	227	202	    } else {
 	228	203	      // Else check if the requirements that are in use have all have interruptible commands,
 	229	204	      // and if so, interrupt those commands and schedule the new command.
 	230	205	      for (Subsystem requirement : requirements) {
 	231	206	        Command requiring = requiring(requirement);
 	232	207	        if (requiring != null
 	233	208	            && requiring.getInterruptionBehavior() == InterruptionBehavior.kCancelIncoming) {
 	234	209	          return;
 	235	210	        }
 	236	211	      }
 	237	212	      for (Subsystem requirement : requirements) {
 	238	213	        Command requiring = requiring(requirement);
 	239	214	        if (requiring != null) {
-	240	 	          cancel(requiring);
+	 	215	          cancel(requiring, Optional.of(command));
 	241	216	        }
 	242	217	      }
 	243	218	      initCommand(command, requirements);
 	244	219	    }
 	245	220	  }
+	 	221	
+	 	222	  /**
+	 	223	   * Schedules multiple commands for execution. Does nothing for commands already scheduled.
+	 	224	   *
+	 	225	   * <p>WARNING: using this function directly can often lead to unexpected behavior and should be
+	 	226	   * avoided. Instead Triggers should be used to schedule Commands.
+	 	227	   *
+	 	228	   * @param commands the commands to schedule. No-op on null.
+	 	229	   */
+	 	230	  public void schedule(Command... commands) {
+	 	231	    for (Command command : commands) {
+	 	232	      schedule(command);
+	 	233	    }
+	 	234	  }
+	 	235	
+	 	236	  /**
+	 	237	   * Runs a single iteration of the scheduler. The execution occurs in the following order:
+	 	238	   *
+	 	239	   * <p>Subsystem periodic methods are called.
+	 	240	   *
+	 	241	   * <p>Button bindings are polled, and new commands are scheduled from them.
+	 	242	   *
+	 	243	   * <p>Currently-scheduled commands are executed.
+	 	244	   *
+	 	245	   * <p>End conditions are checked on currently-scheduled commands, and commands that are finished

v2027.0.0-alpha-2 | v2023.4.3/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/CommandScheduler.java#L181-L191 @ <source/docs/software/commandbased/commands-v2/command-scheduler.rst:39>

-	181	 	  private void initCommand(Command command, Set<Subsystem> requirements) {
-	182	 	    m_scheduledCommands.add(command);
-	183	 	    for (Subsystem requirement : requirements) {
-	184	 	      m_requirements.put(requirement, command);
 	185	181	    }
-	186	 	    command.initialize();
-	187	 	    for (Consumer<Command> action : m_initActions) {
-	188	 	      action.accept(command);
+	 	182	    if (m_inRunLoop) {
+	 	183	      m_toSchedule.add(command);
+	 	184	      return;
 	189	185	    }
 	190	186	
-	191	 	    m_watchdog.addEpoch(command.getName() + ".initialize()");
+	 	187	    requireNotComposed(command);
+	 	188	
+	 	189	    // Do nothing if the scheduler is disabled, the robot is disabled and the command doesn't
+	 	190	    // run when disabled, or the command is already scheduled.
+	 	191	    if (m_disabled

v2027.0.0-alpha-2 | v2023.4.3/wpilibNewCommands/src/main/native/cpp/frc2/command/CommandScheduler.cpp#L114-L159 @ <source/docs/software/commandbased/commands-v2/command-scheduler.rst:47>

-	114	 	void CommandScheduler::Schedule(Command* command) {
-	115	 	  if (m_impl->inRunLoop) {
-	116	 	    m_impl->toSchedule.emplace_back(command);
-	117	 	    return;
-	118	 	  }
-	119	 	
-	120	 	  RequireUngrouped(command);
-	121	 	
-	122	 	  if (m_impl->disabled || m_impl->scheduledCommands.contains(command) ||
-	123	 	      (frc::RobotState::IsDisabled() && !command->RunsWhenDisabled())) {
-	124	 	    return;
-	125	 	  }
-	126	 	
-	127	 	  const auto& requirements = command->GetRequirements();
-	128	 	
-	129	 	  wpi::SmallVector<Command*, 8> intersection;
-	130	 	
 	131	114	  bool isDisjoint = true;
 	132	115	  bool allInterruptible = true;
 	133	116	  for (auto&& i1 : m_impl->requirements) {
 	134	117	    if (requirements.find(i1.first) != requirements.end()) {
 	135	118	      isDisjoint = false;
 	136	119	      allInterruptible &= (i1.second->GetInterruptionBehavior() ==
 	137	120	                           Command::InterruptionBehavior::kCancelSelf);
 	138	121	      intersection.emplace_back(i1.second);
 	139	122	    }
 	140	123	  }
 	141	124	
 	142	125	  if (isDisjoint || allInterruptible) {
 	143	126	    if (allInterruptible) {
 	144	127	      for (auto&& cmdToCancel : intersection) {
-	145	 	        Cancel(cmdToCancel);
+	 	128	        Cancel(cmdToCancel, std::make_optional(command));
 	146	129	      }
 	147	130	    }
 	148	131	    m_impl->scheduledCommands.insert(command);
 	149	132	    for (auto&& requirement : requirements) {
 	150	133	      m_impl->requirements[requirement] = command;
 	151	134	    }
 	152	135	    command->Initialize();
 	153	136	    for (auto&& action : m_impl->initActions) {
 	154	137	      action(*command);
 	155	138	    }
 	156	139	    m_watchdog.AddEpoch(command->GetName() + ".Initialize()");
 	157	140	  }
 	158	141	}
 	159	142	
+	 	143	void CommandScheduler::Schedule(std::span<Command* const> commands) {
+	 	144	  for (auto command : commands) {
+	 	145	    Schedule(command);
+	 	146	  }
+	 	147	}
+	 	148	
+	 	149	void CommandScheduler::Schedule(std::initializer_list<Command*> commands) {
+	 	150	  for (auto command : commands) {
+	 	151	    Schedule(command);
+	 	152	  }
+	 	153	}
+	 	154	
+	 	155	void CommandScheduler::Schedule(const CommandPtr& command) {
+	 	156	  Schedule(command.get());
+	 	157	}
+	 	158	
+	 	159	void CommandScheduler::Schedule(CommandPtr&& command) {

v2027.0.0-alpha-2 | v2023.4.3/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/CommandScheduler.java#L278-L285 @ <source/docs/software/commandbased/commands-v2/command-scheduler.rst:67>

-	278	 	    // Run the periodic method of all registered subsystems.
-	279	 	    for (Subsystem subsystem : m_subsystems.keySet()) {
-	280	 	      subsystem.periodic();
-	281	 	      if (RobotBase.isSimulation()) {
-	282	 	        subsystem.simulationPeriodic();
+	 	278	      if (isDisabled && !command.runsWhenDisabled()) {
+	 	279	        cancel(command, kNoInterruptor);
+	 	280	        continue;
 	283	281	      }
-	284	 	      m_watchdog.addEpoch(subsystem.getClass().getSimpleName() + ".periodic()");
-	285	 	    }
+	 	282	
+	 	283	      command.execute();
+	 	284	      for (Consumer<Command> action : m_executeActions) {
+	 	285	        action.accept(command);

v2027.0.0-alpha-2 | v2023.4.3/wpilibNewCommands/src/main/native/cpp/frc2/command/CommandScheduler.cpp#L183-L190 @ <source/docs/software/commandbased/commands-v2/command-scheduler.rst:75>

-	183	 	  // Run the periodic method of all registered subsystems.
-	184	 	  for (auto&& subsystem : m_impl->subsystems) {
-	185	 	    subsystem.getFirst()->Periodic();
-	186	 	    if constexpr (frc::RobotBase::IsSimulation()) {
-	187	 	      subsystem.getFirst()->SimulationPeriodic();
-	188	 	    }
-	189	 	    m_watchdog.AddEpoch("Subsystem Periodic()");
-	190	 	  }
+	 	183	  frc::EventLoop* loopCache = m_impl->activeButtonLoop;
+	 	184	  // Poll buttons for new commands to add.
+	 	185	  loopCache->Poll();
+	 	186	  m_watchdog.AddEpoch("buttons.Run()");
+	 	187	
+	 	188	  bool isDisabled = frc::RobotState::IsDisabled();
+	 	189	  // create a new set to avoid iterator invalidation.
+	 	190	  for (Command* command : wpi::SmallSet(m_impl->scheduledCommands)) {

v2027.0.0-alpha-2 | v2023.4.3/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/CommandScheduler.java#L290-L292 @ <source/docs/software/commandbased/commands-v2/command-scheduler.rst:93>

-	290	 	    // Poll buttons for new commands to add.
-	291	 	    loopCache.poll();
-	292	 	    m_watchdog.addEpoch("buttons.run()");
+	 	290	        command.end(false);
+	 	291	        for (Consumer<Command> action : m_finishActions) {
+	 	292	          action.accept(command);

v2027.0.0-alpha-2 | v2023.4.3/wpilibNewCommands/src/main/native/cpp/frc2/command/CommandScheduler.cpp#L195-L197 @ <source/docs/software/commandbased/commands-v2/command-scheduler.rst:101>

-	195	 	  // Poll buttons for new commands to add.
-	196	 	  loopCache->Poll();
-	197	 	  m_watchdog.AddEpoch("buttons.Run()");
+	 	195	    if (isDisabled && !command->RunsWhenDisabled()) {
+	 	196	      Cancel(command, std::nullopt);
+	 	197	      continue;

v2027.0.0-alpha-2 | v2023.4.3/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/CommandScheduler.java#L295-L325 @ <source/docs/software/commandbased/commands-v2/command-scheduler.rst:117>

-	295	 	    // Run scheduled commands, remove finished commands.
-	296	 	    for (Iterator<Command> iterator = m_scheduledCommands.iterator(); iterator.hasNext(); ) {
-	297	 	      Command command = iterator.next();
+	 	295	        iterator.remove();
 	298	296	
-	299	 	      if (!command.runsWhenDisabled() && RobotState.isDisabled()) {
-	300	 	        command.end(true);
-	301	 	        for (Consumer<Command> action : m_interruptActions) {
-	302	 	          action.accept(command);
-	303	 	        }
 	304	297	        m_requirements.keySet().removeAll(command.getRequirements());
-	305	 	        iterator.remove();
-	306	 	        m_watchdog.addEpoch(command.getName() + ".end(true)");
-	307	 	        continue;
+	 	298	        m_watchdog.addEpoch(command.getName() + ".end(false)");
 	308	299	      }
+	 	300	    }
+	 	301	    m_inRunLoop = false;
 	309	302	
-	310	 	      command.execute();
-	311	 	      for (Consumer<Command> action : m_executeActions) {
-	312	 	        action.accept(command);
-	313	 	      }
-	314	 	      m_watchdog.addEpoch(command.getName() + ".execute()");
-	315	 	      if (command.isFinished()) {
-	316	 	        command.end(false);
-	317	 	        for (Consumer<Command> action : m_finishActions) {
-	318	 	          action.accept(command);
-	319	 	        }
-	320	 	        iterator.remove();
+	 	303	    // Schedule/cancel commands from queues populated during loop
+	 	304	    for (Command command : m_toSchedule) {
+	 	305	      schedule(command);
+	 	306	    }
 	321	307	
-	322	 	        m_requirements.keySet().removeAll(command.getRequirements());
-	323	 	        m_watchdog.addEpoch(command.getName() + ".end(false)");
+	 	308	    for (int i = 0; i < m_toCancelCommands.size(); i++) {
+	 	309	      cancel(m_toCancelCommands.get(i), m_toCancelInterruptors.get(i));
+	 	310	    }
+	 	311	
+	 	312	    m_toSchedule.clear();
+	 	313	    m_toCancelCommands.clear();
+	 	314	    m_toCancelInterruptors.clear();
+	 	315	
+	 	316	    // Add default commands for un-required registered subsystems.
+	 	317	    for (Map.Entry<Subsystem, Command> subsystemCommand : m_subsystems.entrySet()) {
+	 	318	      if (!m_requirements.containsKey(subsystemCommand.getKey())
+	 	319	          && subsystemCommand.getValue() != null) {
+	 	320	        schedule(subsystemCommand.getValue());
 	324	321	      }
 	325	322	    }
+	 	323	
+	 	324	    m_watchdog.disable();
+	 	325	    if (m_watchdog.isExpired()) {

v2027.0.0-alpha-2 | v2023.4.3/wpilibNewCommands/src/main/native/cpp/frc2/command/CommandScheduler.cpp#L201-L226 @ <source/docs/software/commandbased/commands-v2/command-scheduler.rst:126>

-	201	 	  for (Command* command : m_impl->scheduledCommands) {
-	202	 	    if (!command->RunsWhenDisabled() && frc::RobotState::IsDisabled()) {
-	203	 	      Cancel(command);
-	204	 	      continue;
-	205	 	    }
-	206	 	
-	207	 	    command->Execute();
 	208	201	    for (auto&& action : m_impl->executeActions) {
 	209	202	      action(*command);
 	210	203	    }
 	211	204	    m_watchdog.AddEpoch(command->GetName() + ".Execute()");
 	212	205	
 	213	206	    if (command->IsFinished()) {
+	 	207	      m_impl->scheduledCommands.erase(command);
 	214	208	      command->End(false);
 	215	209	      for (auto&& action : m_impl->finishActions) {
 	216	210	        action(*command);
 	217	211	      }
 	218	212	
 	219	213	      for (auto&& requirement : command->GetRequirements()) {
 	220	214	        m_impl->requirements.erase(requirement);
 	221	215	      }
 	222	216	
-	223	 	      m_impl->scheduledCommands.erase(command);
 	224	217	      m_watchdog.AddEpoch(command->GetName() + ".End(false)");
+	 	218	      // remove owned commands after everything else is done
+	 	219	      m_impl->ownedCommands.erase(command);
 	225	220	    }
 	226	221	  }
+	 	222	
+	 	223	  // Add default commands for un-required registered subsystems.
+	 	224	  for (auto&& subsystem : m_impl->subsystems) {
+	 	225	    auto s = m_impl->requirements.find(subsystem.getFirst());
+	 	226	    if (s == m_impl->requirements.end() && subsystem.getSecond()) {

v2027.0.0-alpha-2 | v2023.4.3/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/CommandScheduler.java#L340-L346 @ <source/docs/software/commandbased/commands-v2/command-scheduler.rst:141>

-	340	 	    // Add default commands for un-required registered subsystems.
-	341	 	    for (Map.Entry<Subsystem, Command> subsystemCommand : m_subsystems.entrySet()) {
-	342	 	      if (!m_requirements.containsKey(subsystemCommand.getKey())
-	343	 	          && subsystemCommand.getValue() != null) {
-	344	 	        schedule(subsystemCommand.getValue());
+	 	340	      if (subsystem == null) {
+	 	341	        DriverStation.reportWarning("Tried to register a null subsystem", true);
+	 	342	        continue;
 	345	343	      }
-	346	 	    }
+	 	344	      if (m_subsystems.containsKey(subsystem)) {
+	 	345	        DriverStation.reportWarning("Tried to register an already-registered subsystem", true);
+	 	346	        continue;

v2027.0.0-alpha-2 | v2023.4.3/wpilibNewCommands/src/main/native/cpp/frc2/command/CommandScheduler.cpp#L240-L246 @ <source/docs/software/commandbased/commands-v2/command-scheduler.rst:149>

-	240	 	  // Add default commands for un-required registered subsystems.
-	241	 	  for (auto&& subsystem : m_impl->subsystems) {
-	242	 	    auto s = m_impl->requirements.find(subsystem.getFirst());
-	243	 	    if (s == m_impl->requirements.end() && subsystem.getSecond()) {
-	244	 	      Schedule({subsystem.getSecond().get()});
-	245	 	    }
+	 	240	    return;
 	246	241	  }
+	 	242	
+	 	243	  m_impl->subsystems[subsystem] = nullptr;
+	 	244	}
+	 	245	
+	 	246	void CommandScheduler::UnregisterSubsystem(Subsystem* subsystem) {

v2027.0.0-alpha-2 | v2024.1.1-beta-2/wpilibjExamples/src/main/java/edu/wpi/first/wpilibj/examples/hatchbotinlined/RobotContainer.java#L73-L88 @ <source/docs/software/commandbased/commands-v2/command-scheduler.rst:179>

-	73	 	    // Set the scheduler to log Shuffleboard events for command initialize, interrupt, finish
-	74	 	    CommandScheduler.getInstance()
-	75	 	        .onCommandInitialize(
-	76	 	            command ->
-	77	 	                Shuffleboard.addEventMarker(
-	78	 	                    "Command initialized", command.getName(), EventImportance.kNormal));
-	79	 	    CommandScheduler.getInstance()
-	80	 	        .onCommandInterrupt(
-	81	 	            command ->
-	82	 	                Shuffleboard.addEventMarker(
-	83	 	                    "Command interrupted", command.getName(), EventImportance.kNormal));
-	84	 	    CommandScheduler.getInstance()
-	85	 	        .onCommandFinish(
-	86	 	            command ->
-	87	 	                Shuffleboard.addEventMarker(
-	88	 	                    "Command finished", command.getName(), EventImportance.kNormal));
+	 	73	   * Use this method to define your button->command mappings. Buttons can be created by
+	 	74	   * instantiating a {@link edu.wpi.first.wpilibj.GenericHID} or one of its subclasses ({@link
+	 	75	   * edu.wpi.first.wpilibj.Joystick} or {@link PS4Controller}), and then passing it to a {@link
+	 	76	   * edu.wpi.first.wpilibj2.command.button.JoystickButton}.
+	 	77	   */
+	 	78	  private void configureButtonBindings() {
+	 	79	    // Grab the hatch when the Circle button is pressed.
+	 	80	    m_driverController.circle().onTrue(m_hatchSubsystem.grabHatchCommand());
+	 	81	    // Release the hatch when the Square button is pressed.
+	 	82	    m_driverController.square().onTrue(m_hatchSubsystem.releaseHatchCommand());
+	 	83	    // While holding R1, drive at half speed
+	 	84	    m_driverController
+	 	85	        .R1()
+	 	86	        .onTrue(Commands.runOnce(() -> m_robotDrive.setMaxOutput(0.5)))
+	 	87	        .onFalse(Commands.runOnce(() -> m_robotDrive.setMaxOutput(1)));
+	 	88	  }

v2027.0.0-alpha-2 | v2024.1.1-beta-2/wpilibcExamples/src/main/cpp/examples/HatchbotInlined/cpp/RobotContainer.cpp#L23-L47 @ <source/docs/software/commandbased/commands-v2/command-scheduler.rst:187>

-	23	 	  // Log Shuffleboard events for command initialize, execute, finish, interrupt
-	24	 	  frc2::CommandScheduler::GetInstance().OnCommandInitialize(
-	25	 	      [](const frc2::Command& command) {
-	26	 	        frc::Shuffleboard::AddEventMarker(
-	27	 	            "Command initialized", command.GetName(),
-	28	 	            frc::ShuffleboardEventImportance::kNormal);
-	29	 	      });
-	30	 	  frc2::CommandScheduler::GetInstance().OnCommandExecute(
-	31	 	      [](const frc2::Command& command) {
-	32	 	        frc::Shuffleboard::AddEventMarker(
-	33	 	            "Command executed", command.GetName(),
-	34	 	            frc::ShuffleboardEventImportance::kNormal);
-	35	 	      });
-	36	 	  frc2::CommandScheduler::GetInstance().OnCommandFinish(
-	37	 	      [](const frc2::Command& command) {
-	38	 	        frc::Shuffleboard::AddEventMarker(
-	39	 	            "Command finished", command.GetName(),
-	40	 	            frc::ShuffleboardEventImportance::kNormal);
-	41	 	      });
-	42	 	  frc2::CommandScheduler::GetInstance().OnCommandInterrupt(
-	43	 	      [](const frc2::Command& command) {
-	44	 	        frc::Shuffleboard::AddEventMarker(
-	45	 	            "Command interrupted", command.GetName(),
-	46	 	            frc::ShuffleboardEventImportance::kNormal);
-	47	 	      });
+	 	23	  // Configure the button bindings
+	 	24	  ConfigureButtonBindings();
+	 	25	
+	 	26	  // Set up default drive command
+	 	27	  m_drive.SetDefaultCommand(frc2::cmd::Run(
+	 	28	      [this] {
+	 	29	        m_drive.ArcadeDrive(-m_driverController.GetLeftY(),
+	 	30	                            -m_driverController.GetRightX());
+	 	31	      },
+	 	32	      {&m_drive}));
+	 	33	}
+	 	34	
+	 	35	void RobotContainer::ConfigureButtonBindings() {
+	 	36	  // Configure your button bindings here
+	 	37	
+	 	38	  // Grab the hatch when the 'Circle' button is pressed.
+	 	39	  m_driverController.Circle().OnTrue(m_hatch.GrabHatchCommand());
+	 	40	  // Release the hatch when the 'Square' button is pressed.
+	 	41	  m_driverController.Square().OnTrue(m_hatch.ReleaseHatchCommand());
+	 	42	  // While holding R1, drive at half speed
+	 	43	  m_driverController.R1()
+	 	44	      .OnTrue(frc2::cmd::RunOnce([this] { m_drive.SetMaxOutput(0.5); }, {}))
+	 	45	      .OnFalse(frc2::cmd::RunOnce([this] { m_drive.SetMaxOutput(1.0); }, {}));
+	 	46	}
+	 	47	

v2027.0.0-alpha-2 | v2024.1.1/wpilibjExamples/src/main/java/edu/wpi/first/wpilibj/examples/hatchbottraditional/subsystems/HatchSubsystem.java#L5-EOF @ <source/docs/software/commandbased/commands-v2/subsystems.rst:77>

 	5	5	package edu.wpi.first.wpilibj.examples.hatchbottraditional.subsystems;
 	6	6	
 	7	7	import static edu.wpi.first.wpilibj.DoubleSolenoid.Value.kForward;
 	8	8	import static edu.wpi.first.wpilibj.DoubleSolenoid.Value.kReverse;
 	9	9	
 	10	10	import edu.wpi.first.util.sendable.SendableBuilder;
 	11	11	import edu.wpi.first.wpilibj.DoubleSolenoid;
 	12	12	import edu.wpi.first.wpilibj.PneumaticsModuleType;
 	13	13	import edu.wpi.first.wpilibj.examples.hatchbottraditional.Constants.HatchConstants;
 	14	14	import edu.wpi.first.wpilibj2.command.SubsystemBase;
 	15	15	
 	16	16	/** A hatch mechanism actuated by a single {@link DoubleSolenoid}. */
 	17	17	public class HatchSubsystem extends SubsystemBase {
 	18	18	  private final DoubleSolenoid m_hatchSolenoid =
 	19	19	      new DoubleSolenoid(
+	 	20	          0,
 	20	21	          PneumaticsModuleType.CTREPCM,
 	21	22	          HatchConstants.kHatchSolenoidPorts[0],
 	22	23	          HatchConstants.kHatchSolenoidPorts[1]);
 	23	24	
 	24	25	  /** Grabs the hatch. */
 	25	26	  public void grabHatch() {
 	26	27	    m_hatchSolenoid.set(kForward);
 	27	28	  }
 	28	29	
 	29	30	  /** Releases the hatch. */
 	30	31	  public void releaseHatch() {
 	31	32	    m_hatchSolenoid.set(kReverse);
 	32	33	  }
 	33	34	
 	34	35	  @Override
 	35	36	  public void initSendable(SendableBuilder builder) {
 	36	37	    super.initSendable(builder);
 	37	38	    // Publish the solenoid state to telemetry.
 	38	39	    builder.addBooleanProperty("extended", () -> m_hatchSolenoid.get() == kForward, null);
 	39	40	  }
 	40	41	}
 	41	42	

v2027.0.0-alpha-2 | v2024.1.1/wpilibcExamples/src/main/cpp/examples/HatchbotTraditional/cpp/subsystems/HatchSubsystem.cpp#L5-EOF @ <source/docs/software/commandbased/commands-v2/subsystems.rst:93>

 	5	5	#include "subsystems/HatchSubsystem.h"
 	6	6	
 	7	7	#include <wpi/sendable/SendableBuilder.h>
 	8	8	
 	9	9	using namespace HatchConstants;
 	10	10	
 	11	11	HatchSubsystem::HatchSubsystem()
-	12	 	    : m_hatchSolenoid{frc::PneumaticsModuleType::CTREPCM,
+	 	12	    : m_hatchSolenoid{0, frc::PneumaticsModuleType::CTREPCM,
 	13	13	                      kHatchSolenoidPorts[0], kHatchSolenoidPorts[1]} {}
 	14	14	
 	15	15	void HatchSubsystem::GrabHatch() {
 	16	16	  m_hatchSolenoid.Set(frc::DoubleSolenoid::kForward);
 	17	17	}
 	18	18	
 	19	19	void HatchSubsystem::ReleaseHatch() {
 	20	20	  m_hatchSolenoid.Set(frc::DoubleSolenoid::kReverse);
 	21	21	}
 	22	22	
 	23	23	void HatchSubsystem::InitSendable(wpi::SendableBuilder& builder) {
 	24	24	  SubsystemBase::InitSendable(builder);
 	25	25	
 	26	26	  // Publish the solenoid state to telemetry.
 	27	27	  builder.AddBooleanProperty(
 	28	28	      "extended",
 	29	29	      [this] { return m_hatchSolenoid.Get() == frc::DoubleSolenoid::kForward; },
 	30	30	      nullptr);
 	31	31	}
 	32	32	

v2027.0.0-alpha-2 | v2024.1.1/wpilibjExamples/src/main/java/edu/wpi/first/wpilibj/examples/hatchbotinlined/subsystems/HatchSubsystem.java#L5-EOF @ <source/docs/software/commandbased/commands-v2/subsystems.rst:115>

 	5	5	package edu.wpi.first.wpilibj.examples.hatchbotinlined.subsystems;
 	6	6	
 	7	7	import static edu.wpi.first.wpilibj.DoubleSolenoid.Value.kForward;
 	8	8	import static edu.wpi.first.wpilibj.DoubleSolenoid.Value.kReverse;
 	9	9	
 	10	10	import edu.wpi.first.util.sendable.SendableBuilder;
 	11	11	import edu.wpi.first.wpilibj.DoubleSolenoid;
 	12	12	import edu.wpi.first.wpilibj.PneumaticsModuleType;
 	13	13	import edu.wpi.first.wpilibj.examples.hatchbotinlined.Constants.HatchConstants;
 	14	14	import edu.wpi.first.wpilibj2.command.Command;
 	15	15	import edu.wpi.first.wpilibj2.command.SubsystemBase;
 	16	16	
 	17	17	/** A hatch mechanism actuated by a single {@link edu.wpi.first.wpilibj.DoubleSolenoid}. */
 	18	18	public class HatchSubsystem extends SubsystemBase {
 	19	19	  private final DoubleSolenoid m_hatchSolenoid =
 	20	20	      new DoubleSolenoid(
+	 	21	          0,
 	21	22	          PneumaticsModuleType.CTREPCM,
 	22	23	          HatchConstants.kHatchSolenoidPorts[0],
 	23	24	          HatchConstants.kHatchSolenoidPorts[1]);
 	24	25	
 	25	26	  /** Grabs the hatch. */
 	26	27	  public Command grabHatchCommand() {
 	27	28	    // implicitly require `this`
 	28	29	    return this.runOnce(() -> m_hatchSolenoid.set(kForward));
 	29	30	  }
 	30	31	
 	31	32	  /** Releases the hatch. */
 	32	33	  public Command releaseHatchCommand() {
 	33	34	    // implicitly require `this`
 	34	35	    return this.runOnce(() -> m_hatchSolenoid.set(kReverse));
 	35	36	  }
 	36	37	
 	37	38	  @Override
 	38	39	  public void initSendable(SendableBuilder builder) {
 	39	40	    super.initSendable(builder);
 	40	41	    // Publish the solenoid state to telemetry.
 	41	42	    builder.addBooleanProperty("extended", () -> m_hatchSolenoid.get() == kForward, null);
 	42	43	  }
 	43	44	}
 	44	45	

v2027.0.0-alpha-2 | v2024.1.1/wpilibcExamples/src/main/cpp/examples/HatchbotInlined/cpp/subsystems/HatchSubsystem.cpp#L5-EOF @ <source/docs/software/commandbased/commands-v2/subsystems.rst:131>

 	5	5	#include "subsystems/HatchSubsystem.h"
 	6	6	
 	7	7	#include <wpi/sendable/SendableBuilder.h>
 	8	8	
 	9	9	using namespace HatchConstants;
 	10	10	
 	11	11	HatchSubsystem::HatchSubsystem()
-	12	 	    : m_hatchSolenoid{frc::PneumaticsModuleType::CTREPCM,
+	 	12	    : m_hatchSolenoid{0, frc::PneumaticsModuleType::CTREPCM,
 	13	13	                      kHatchSolenoidPorts[0], kHatchSolenoidPorts[1]} {}
 	14	14	
 	15	15	frc2::CommandPtr HatchSubsystem::GrabHatchCommand() {
 	16	16	  // implicitly require `this`
 	17	17	  return this->RunOnce(
 	18	18	      [this] { m_hatchSolenoid.Set(frc::DoubleSolenoid::kForward); });
 	19	19	}
 	20	20	
 	21	21	frc2::CommandPtr HatchSubsystem::ReleaseHatchCommand() {
 	22	22	  // implicitly require `this`
 	23	23	  return this->RunOnce(
 	24	24	      [this] { m_hatchSolenoid.Set(frc::DoubleSolenoid::kReverse); });
 	25	25	}
 	26	26	
 	27	27	void HatchSubsystem::InitSendable(wpi::SendableBuilder& builder) {
 	28	28	  SubsystemBase::InitSendable(builder);
 	29	29	
 	30	30	  // Publish the solenoid state to telemetry.
 	31	31	  builder.AddBooleanProperty(
 	32	32	      "extended",
 	33	33	      [this] { return m_hatchSolenoid.Get() == frc::DoubleSolenoid::kForward; },
 	34	34	      nullptr);
 	35	35	}
 	36	36	

v2027.0.0-alpha-2 | v2024.1.1-beta-4/wpilibjExamples/src/main/java/edu/wpi/first/wpilibj/examples/statespacedifferentialdrivesimulation/subsystems/DriveSubsystem.java#L117-L125 @ <source/docs/software/commandbased/commands-v2/subsystems.rst:158>

-	117	 	  @Override
-	118	 	  public void periodic() {
-	119	 	    // Update the odometry in the periodic block
-	120	 	    m_odometry.update(
-	121	 	        Rotation2d.fromDegrees(getHeading()),
-	122	 	        m_leftEncoder.getDistance(),
-	123	 	        m_rightEncoder.getDistance());
-	124	 	    m_fieldSim.setRobotPose(getPose());
-	125	 	  }
+	 	117	

v2027.0.0-alpha-2 | v2024.1.1-beta-4/wpilibcExamples/src/main/cpp/examples/StateSpaceDifferentialDriveSimulation/include/subsystems/DriveSubsystem.h#L30 @ <source/docs/software/commandbased/commands-v2/subsystems.rst:166>

-	30	 	  void Periodic() override;
+	 	30	

v2027.0.0-alpha-2 | v2024.1.1-beta-4/wpilibcExamples/src/main/cpp/examples/StateSpaceDifferentialDriveSimulation/cpp/subsystems/DriveSubsystem.cpp#L30-L36 @ <source/docs/software/commandbased/commands-v2/subsystems.rst:174>

-	30	 	void DriveSubsystem::Periodic() {
-	31	 	  // Implementation of subsystem periodic method goes here.
-	32	 	  m_odometry.Update(m_gyro.GetRotation2d(),
-	33	 	                    units::meter_t{m_leftEncoder.GetDistance()},
-	34	 	                    units::meter_t{m_rightEncoder.GetDistance()});
-	35	 	  m_fieldSim.SetRobotPose(m_odometry.GetPose());
-	36	 	}
+	 	30	

@sciencewhiz
Copy link
Collaborator Author

\inspector fix all

@sciencewhiz sciencewhiz marked this pull request as ready for review November 22, 2025 23:32
Co-authored-by: Ryan Blue <[email protected]>
@jasondaming jasondaming requested a review from rzblue November 27, 2025 11:42
@sciencewhiz sciencewhiz merged commit 4aaa40b into wpilibsuite:2027 Nov 29, 2025
10 checks passed
@sciencewhiz sciencewhiz deleted the cherry-pick-3117 branch November 29, 2025 03:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants