SCRIPT Move cc files

This commit is contained in:
PJ Reiniger
2025-11-07 19:55:39 -05:00
committed by Peter Johnson
parent 10b4a0c971
commit 7ca1be9bae
1197 changed files with 0 additions and 0 deletions

View File

@@ -0,0 +1,497 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#pragma once
#include <functional>
#include <memory>
#include <optional>
#include <string>
#include <units/time.h>
#include <wpi/Demangle.h>
#include <wpi/SmallSet.h>
#include <wpi/StackTrace.h>
#include <wpi/sendable/Sendable.h>
#include "frc2/command/Requirements.h"
#include "frc2/command/Subsystem.h"
namespace frc2 {
/**
* A state machine representing a complete action to be performed by the robot.
* Commands are run by the CommandScheduler, and can be composed into
* CommandGroups to allow users to build complicated multi-step actions without
* the need to roll the state machine logic themselves.
*
* <p>Commands are run synchronously from the main robot loop; no
* multithreading is used, unless specified explicitly from the command
* implementation.
*
* <p>Note: ALWAYS create a subclass by extending CommandHelper<Base, Subclass>,
* or decorators will not function!
*
* This class is provided by the NewCommands VendorDep
*
* @see CommandScheduler
* @see CommandHelper
*/
class Command : public wpi::Sendable, public wpi::SendableHelper<Command> {
public:
~Command() override;
Command(const Command&) = default;
Command& operator=(const Command& rhs);
Command(Command&&) = default;
Command& operator=(Command&&) = default;
/**
* The initial subroutine of a command. Called once when the command is
* initially scheduled.
*/
virtual void Initialize();
/**
* The main body of a command. Called repeatedly while the command is
* scheduled.
*/
virtual void Execute();
/**
* The action to take when the command ends. Called when either the command
* finishes normally, or when it interrupted/canceled.
*
* @param interrupted whether the command was interrupted/canceled
*/
virtual void End(bool interrupted);
/**
* Whether the command has finished. Once a command finishes, the scheduler
* will call its end() method and un-schedule it.
*
* @return whether the command has finished.
*/
virtual bool IsFinished() { return false; }
/**
* Specifies the set of subsystems used by this command. Two commands cannot
* use the same subsystem at the same time. If another command is scheduled
* that shares a requirement, GetInterruptionBehavior() will be checked and
* followed. If no subsystems are required, return an empty set.
*
* <p>Note: it is recommended that user implementations contain the
* requirements as a field, and return that field here, rather than allocating
* a new set every time this is called.
*
* @return the set of subsystems that are required
* @see InterruptionBehavior
*/
virtual wpi::SmallSet<Subsystem*, 4> GetRequirements() const;
/**
* Adds the specified Subsystem requirements to the command.
*
* The scheduler will prevent two commands that require the same subsystem
* from being scheduled simultaneously.
*
* Note that the scheduler determines the requirements of a command when it
* is scheduled, so this method should normally be called from the command's
* constructor.
*
* While this overload can be used with {@code AddRequirements({&subsystem1,
* &subsystem2})}, {@code AddRequirements({&subsystem})} selects the {@code
* AddRequirements(Subsystem*)} overload, which will function identically but
* may cause warnings about redundant braces.
*
* @param requirements the Subsystem requirements to add, which can be
* implicitly constructed from an initializer list or a span
*/
void AddRequirements(Requirements requirements);
/**
* Adds the specified Subsystem requirements to the command.
*
* The scheduler will prevent two commands that require the same subsystem
* from being scheduled simultaneously.
*
* Note that the scheduler determines the requirements of a command when it
* is scheduled, so this method should normally be called from the command's
* constructor.
*
* @param requirements the Subsystem requirements to add
*/
void AddRequirements(wpi::SmallSet<Subsystem*, 4> requirements);
/**
* Adds the specified Subsystem requirement to the command.
*
* The scheduler will prevent two commands that require the same subsystem
* from being scheduled simultaneously.
*
* Note that the scheduler determines the requirements of a command when it
* is scheduled, so this method should normally be called from the command's
* constructor.
*
* @param requirement the Subsystem requirement to add
*/
void AddRequirements(Subsystem* requirement);
/**
* Gets the name of this Command.
*
* @return Name
*/
std::string GetName() const;
/**
* Sets the name of this Command.
*
* @param name name
*/
void SetName(std::string_view name);
/**
* Gets the subsystem name of this Command.
*
* @return Subsystem name
*/
std::string GetSubsystem() const;
/**
* Sets the subsystem name of this Command.
*
* @param subsystem subsystem name
*/
void SetSubsystem(std::string_view subsystem);
/**
* An enum describing the command's behavior when another command with a
* shared requirement is scheduled.
*/
enum class InterruptionBehavior {
/**
* This command ends, End(true) is called, and the incoming command is
* scheduled normally.
*
* <p>This is the default behavior.
*/
kCancelSelf,
/** This command continues, and the incoming command is not scheduled. */
kCancelIncoming
};
friend class CommandPtr;
/**
* Decorates this command with a timeout. If the specified timeout is
* exceeded before the command finishes normally, the command will be
* interrupted and un-scheduled.
*
* @param duration the timeout duration
* @return the command with the timeout added
*/
CommandPtr WithTimeout(units::second_t duration) &&;
/**
* Decorates this command with an interrupt condition. If the specified
* condition becomes true before the command finishes normally, the command
* will be interrupted and un-scheduled.
*
* @param condition the interrupt condition
* @return the command with the interrupt condition added
*/
CommandPtr Until(std::function<bool()> condition) &&;
/**
* Decorates this command with a run condition. If the specified condition
* becomes false before the command finishes normally, the command will be
* interrupted and un-scheduled.
*
* @param condition the run condition
* @return the command with the run condition added
*/
CommandPtr OnlyWhile(std::function<bool()> condition) &&;
/**
* Decorates this command with a runnable to run before this command starts.
*
* @param toRun the Runnable to run
* @param requirements the required subsystems
* @return the decorated command
*/
CommandPtr BeforeStarting(std::function<void()> toRun,
Requirements requirements = {}) &&;
/**
* Decorates this command with another command to run before this command
* starts.
*
* @param before the command to run before this one
* @return the decorated command
*/
CommandPtr BeforeStarting(CommandPtr&& before) &&;
/**
* Decorates this command with a runnable to run after the command finishes.
*
* @param toRun the Runnable to run
* @param requirements the required subsystems
* @return the decorated command
*/
CommandPtr AndThen(std::function<void()> toRun,
Requirements requirements = {}) &&;
/**
* Decorates this command with a set of commands to run after it in sequence.
* Often more convenient/less-verbose than constructing a
* SequentialCommandGroup explicitly.
*
* @param next the commands to run next
* @return the decorated command
*/
CommandPtr AndThen(CommandPtr&& next) &&;
/**
* Decorates this command to run repeatedly, restarting it when it ends, until
* this command is interrupted. The decorated command can still be canceled.
*
* @return the decorated command
*/
CommandPtr Repeatedly() &&;
/**
* Decorates this command to run "by proxy" by wrapping it in a ProxyCommand.
* Use this for "forking off" from command compositions when the user does not
* wish to extend the command's requirements to the entire command
* composition. ProxyCommand has unique implications and semantics, see <a
* href="https://docs.wpilib.org/en/stable/docs/software/commandbased/command-compositions.html#scheduling-other-commands">the
* WPILib docs</a> for a full explanation.
*
* <p>This overload transfers command ownership to the returned CommandPtr.
*
* @return the decorated command
* @see ProxyCommand
*/
CommandPtr AsProxy() &&;
/**
* Decorates this command to only run if this condition is not met. If the
* command is already running and the condition changes to true, the command
* will not stop running. The requirements of this command will be kept for
* the new conditional command.
*
* @param condition the condition that will prevent the command from running
* @return the decorated command
*/
CommandPtr Unless(std::function<bool()> condition) &&;
/**
* Decorates this command to only run if this condition is met. If the command
* is already running and the condition changes to false, the command will not
* stop running. The requirements of this command will be kept for the new
* conditional command.
*
* @param condition the condition that will allow the command to run
* @return the decorated command
*/
CommandPtr OnlyIf(std::function<bool()> condition) &&;
/**
* Creates a new command that runs this command and the deadline in parallel,
* finishing (and interrupting this command) when the deadline finishes.
*
* @param deadline the deadline of the command group
* @return the decorated command
* @see DeadlineFor
*/
CommandPtr WithDeadline(CommandPtr&& deadline) &&;
/**
* Decorates this command with a set of commands to run parallel to it, ending
* when the calling command ends and interrupting all the others. Often more
* convenient/less-verbose than constructing a new {@link
* ParallelDeadlineGroup} explicitly.
*
* @param parallel the commands to run in parallel. Note the parallel commands
* will be interupted when the deadline command ends
* @return the decorated command
* @see WithDeadline
*/
CommandPtr DeadlineFor(CommandPtr&& parallel) &&;
/**
* Decorates this command with a set of commands to run parallel to it, ending
* when the last command ends. Often more convenient/less-verbose than
* constructing a new {@link ParallelCommandGroup} explicitly.
*
* @param parallel the commands to run in parallel
* @return the decorated command
*/
CommandPtr AlongWith(CommandPtr&& parallel) &&;
/**
* Decorates this command with a set of commands to run parallel to it, ending
* when the first command ends. Often more convenient/less-verbose than
* constructing a new {@link ParallelRaceGroup} explicitly.
*
* @param parallel the commands to run in parallel
* @return the decorated command
*/
CommandPtr RaceWith(CommandPtr&& parallel) &&;
/**
* Decorates this command to run or stop when disabled.
*
* @param doesRunWhenDisabled true to run when disabled.
* @return the decorated command
*/
CommandPtr IgnoringDisable(bool doesRunWhenDisabled) &&;
/**
* Decorates this command to have a different interrupt behavior.
*
* @param interruptBehavior the desired interrupt behavior
* @return the decorated command
*/
CommandPtr WithInterruptBehavior(
Command::InterruptionBehavior interruptBehavior) &&;
/**
* Decorates this command with a lambda to call on interrupt or end, following
* the command's inherent Command::End(bool) method.
*
* @param end a lambda accepting a boolean parameter specifying whether the
* command was interrupted.
* @return the decorated command
*/
CommandPtr FinallyDo(std::function<void(bool)> end) &&;
/**
* Decorates this command with a lambda to call on interrupt or end, following
* the command's inherent Command::End(bool) method. The provided lambda will
* run identically in both interrupt and end cases.
*
* @param end a lambda to run when the command ends, whether or not it was
* interrupted.
* @return the decorated command
*/
CommandPtr FinallyDo(std::function<void()> end) &&;
/**
* Decorates this command with a lambda to call on interrupt, following the
* command's inherent Command::End(bool) method.
*
* @param handler a lambda to run when the command is interrupted
* @return the decorated command
*/
CommandPtr HandleInterrupt(std::function<void()> handler) &&;
/**
* Decorates this Command with a name.
*
* @param name name
* @return the decorated Command
*/
CommandPtr WithName(std::string_view name) &&;
/**
* Schedules this command.
*
* @deprecated Use CommandScheduler::GetInstance().Schedule() instead
*/
[[deprecated("Use CommandScheduler::GetInstance().Schedule() instead.")]]
void Schedule();
/**
* Cancels this command. Will call End(true). Commands will be canceled
* regardless of interruption behavior.
*/
void Cancel();
/**
* Whether or not the command is currently scheduled. Note that this does not
* detect whether the command is in a composition, only whether it is directly
* being run by the scheduler.
*
* @return Whether the command is scheduled.
*/
bool IsScheduled() const;
/**
* Whether the command requires a given subsystem. Named "HasRequirement"
* rather than "requires" to avoid confusion with Command::Requires(Subsystem)
* -- this may be able to be changed in a few years.
*
* @param requirement the subsystem to inquire about
* @return whether the subsystem is required
*/
bool HasRequirement(Subsystem* requirement) const;
/**
* Whether the command is currently grouped in a command group. Used as extra
* insurance to prevent accidental independent use of grouped commands.
*/
bool IsComposed() const;
/**
* Sets whether the command is currently composed in a command composition.
* Can be used to "reclaim" a command if a composition is no longer going to
* use it. NOT ADVISED!
*/
void SetComposed(bool isComposed);
/**
* Get the stacktrace of where this command was composed, or an empty
* optional. Intended for internal use.
*
* @return optional string representation of the composition site stack trace.
*/
std::optional<std::string> GetPreviousCompositionSite() const;
/**
* Whether the given command should run when the robot is disabled. Override
* to return true if the command should run when disabled.
*
* @return whether the command should run when the robot is disabled
*/
virtual bool RunsWhenDisabled() const { return false; }
/**
* How the command behaves when another command with a shared requirement is
* scheduled.
*
* @return a variant of InterruptionBehavior, defaulting to kCancelSelf.
*/
virtual InterruptionBehavior GetInterruptionBehavior() const {
return InterruptionBehavior::kCancelSelf;
}
/**
* Transfers ownership of this command to a unique pointer. Used for
* decorator methods.
*/
virtual CommandPtr ToPtr() && = 0;
void InitSendable(wpi::SendableBuilder& builder) override;
protected:
Command();
private:
/// Requirements set.
wpi::SmallSet<Subsystem*, 4> m_requirements;
std::optional<std::string> m_previousComposition;
};
/**
* Checks if two commands have disjoint requirement sets.
*
* @param first The first command to check.
* @param second The second command to check.
* @return False if first and second share a requirement.
*/
bool RequirementsDisjoint(Command* first, Command* second);
} // namespace frc2

View File

@@ -0,0 +1,36 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#pragma once
#include <concepts>
#include <memory>
#include <utility>
#include "frc2/command/Command.h"
#include "frc2/command/CommandPtr.h"
namespace frc2 {
/**
* CRTP implementation to allow polymorphic decorator functions in Command.
*
* <p>Note: ALWAYS create a subclass by extending CommandHelper<Base, Subclass>,
* or decorators will not function!
*
* This class is provided by the NewCommands VendorDep
*/
template <std::derived_from<Command> Base, typename CRTP>
class CommandHelper : public Base {
using Base::Base;
public:
CommandHelper() = default;
CommandPtr ToPtr() && override {
return CommandPtr(
std::make_unique<CRTP>(std::move(*static_cast<CRTP*>(this))));
}
};
} // namespace frc2

View File

@@ -0,0 +1,342 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#pragma once
#include <concepts>
#include <functional>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "frc2/command/Command.h"
#include "frc2/command/Requirements.h"
namespace frc2 {
/**
* A wrapper around std::unique_ptr<Command> so commands have move-only
* semantics. Commands should only be stored and passed around when held in a
* CommandPtr instance. For more info, see
* https://github.com/wpilibsuite/allwpilib/issues/4303.
*
* Various classes in the command-based library accept a
* std::unique_ptr<Command>, use CommandPtr::Unwrap to convert.
* CommandPtr::UnwrapVector does the same for vectors.
*/
class [[nodiscard]] CommandPtr final {
public:
explicit CommandPtr(std::unique_ptr<Command>&& command);
template <std::derived_from<Command> T>
// NOLINTNEXTLINE(bugprone-forwarding-reference-overload)
explicit CommandPtr(T&& command)
: CommandPtr(
std::make_unique<std::decay_t<T>>(std::forward<T>(command))) {}
CommandPtr(CommandPtr&&);
CommandPtr& operator=(CommandPtr&&) = default;
explicit CommandPtr(std::nullptr_t) = delete;
/**
* Decorates this command to run repeatedly, restarting it when it ends, until
* this command is interrupted. The decorated command can still be canceled.
*
* @return the decorated command
*/
CommandPtr Repeatedly() &&;
/**
* Decorates this command to run "by proxy" by wrapping it in a ProxyCommand.
* Use this for "forking off" from command compositions when the user does not
* wish to extend the command's requirements to the entire command
* composition. ProxyCommand has unique implications and semantics, see <a
* href="https://docs.wpilib.org/en/stable/docs/software/commandbased/command-compositions.html#scheduling-other-commands">the
* WPILib docs</a> for a full explanation.
*
* @return the decorated command
* @see ProxyCommand
*/
CommandPtr AsProxy() &&;
/**
* Decorates this command to run or stop when disabled.
*
* @param doesRunWhenDisabled true to run when disabled
* @return the decorated command
*/
CommandPtr IgnoringDisable(bool doesRunWhenDisabled) &&;
/**
* Decorates this command to have a different interrupt behavior.
*
* @param interruptBehavior the desired interrupt behavior
* @return the decorated command
*/
CommandPtr WithInterruptBehavior(
Command::InterruptionBehavior interruptBehavior) &&;
/**
* Decorates this command with a runnable to run after the command finishes.
*
* @param toRun the Runnable to run
* @param requirements the required subsystems
* @return the decorated command
*/
CommandPtr AndThen(std::function<void()> toRun,
Requirements requirements = {}) &&;
/**
* Decorates this command with a set of commands to run after it in sequence.
* Often more convenient/less-verbose than constructing a new {@link
* SequentialCommandGroup} explicitly.
*
* @param next the commands to run next
* @return the decorated command
*/
CommandPtr AndThen(CommandPtr&& next) &&;
/**
* Decorates this command with a runnable to run before this command starts.
*
* @param toRun the Runnable to run
* @param requirements the required subsystems
* @return the decorated command
*/
CommandPtr BeforeStarting(std::function<void()> toRun,
Requirements requirements = {}) &&;
/**
* Decorates this command with another command to run before this command
* starts.
*
* @param before the command to run before this one
* @return the decorated command
*/
CommandPtr BeforeStarting(CommandPtr&& before) &&;
/**
* Decorates this command with a timeout. If the specified timeout is
* exceeded before the command finishes normally, the command will be
* interrupted and un-scheduled.
*
* @param duration the timeout duration
* @return the command with the timeout added
*/
CommandPtr WithTimeout(units::second_t duration) &&;
/**
* Decorates this command with an interrupt condition. If the specified
* condition becomes true before the command finishes normally, the command
* will be interrupted and un-scheduled.
*
* @param condition the interrupt condition
* @return the command with the interrupt condition added
*/
CommandPtr Until(std::function<bool()> condition) &&;
/**
* Decorates this command with a run condition. If the specified condition
* becomes false before the command finishes normally, the command will be
* interrupted and un-scheduled.
*
* @param condition the run condition
* @return the command with the run condition added
*/
CommandPtr OnlyWhile(std::function<bool()> condition) &&;
/**
* Decorates this command to only run if this condition is not met. If the
* command is already running and the condition changes to true, the command
* will not stop running. The requirements of this command will be kept for
* the new conditional command.
*
* @param condition the condition that will prevent the command from running
* @return the decorated command
*/
CommandPtr Unless(std::function<bool()> condition) &&;
/**
* Decorates this command to only run if this condition is met. If the command
* is already running and the condition changes to false, the command will not
* stop running. The requirements of this command will be kept for the new
* conditional command.
*
* @param condition the condition that will allow the command to run
* @return the decorated command
*/
CommandPtr OnlyIf(std::function<bool()> condition) &&;
/**
* Creates a new command that runs this command and the deadline in parallel,
* finishing (and interrupting this command) when the deadline finishes.
*
* @param deadline the deadline of the command group
* @return the decorated command
* @see DeadlineFor
*/
CommandPtr WithDeadline(CommandPtr&& deadline) &&;
/**
* Decorates this command with a set of commands to run parallel to it, ending
* when the calling command ends and interrupting all the others. Often more
* convenient/less-verbose than constructing a new {@link
* ParallelDeadlineGroup} explicitly.
*
* @param parallel the commands to run in parallel
* @return the decorated command
*/
[[deprecated("Replace with DeadlineFor")]]
CommandPtr DeadlineWith(CommandPtr&& parallel) &&;
/**
* Decorates this command with a set of commands to run parallel to it, ending
* when the calling command ends and interrupting all the others. Often more
* convenient/less-verbose than constructing a new {@link
* ParallelDeadlineGroup} explicitly.
*
* @param parallel the commands to run in parallel. Note the parallel commands
* will be interupted when the deadline command ends
* @return the decorated command
*/
CommandPtr DeadlineFor(CommandPtr&& parallel) &&;
/**
* Decorates this command with a set of commands to run parallel to it, ending
* when the last command ends. Often more convenient/less-verbose than
* constructing a new {@link ParallelCommandGroup} explicitly.
*
* @param parallel the commands to run in parallel
* @return the decorated command
*/
CommandPtr AlongWith(CommandPtr&& parallel) &&;
/**
* Decorates this command with a set of commands to run parallel to it, ending
* when the first command ends. Often more convenient/less-verbose than
* constructing a new {@link ParallelRaceGroup} explicitly.
*
* @param parallel the commands to run in parallel
* @return the decorated command
*/
CommandPtr RaceWith(CommandPtr&& parallel) &&;
/**
* Decorates this command with a lambda to call on interrupt or end, following
* the command's inherent Command::End(bool) method.
*
* @param end a lambda accepting a boolean parameter specifying whether the
* command was interrupted
* @return the decorated command
*/
CommandPtr FinallyDo(std::function<void(bool)> end) &&;
/**
* Decorates this command with a lambda to call on interrupt or end, following
* the command's inherent Command::End(bool) method. The provided lambda will
* run identically in both interrupt and end cases.
*
* @param end a lambda to run when the command ends, whether or not it was
* interrupted.
* @return the decorated command
*/
CommandPtr FinallyDo(std::function<void()> end) &&;
/**
* Decorates this command with a lambda to call on interrupt, following the
* command's inherent Command::End(bool) method.
*
* @param handler a lambda to run when the command is interrupted
* @return the decorated command
*/
CommandPtr HandleInterrupt(std::function<void()> handler) &&;
/**
* Decorates this Command with a name. Is an inline function for
* Command::SetName(std::string_view);
*
* @param name name
* @return the decorated Command
*/
CommandPtr WithName(std::string_view name) &&;
/**
* Get a raw pointer to the held command.
*/
Command* get() const&;
// Prevent calls on a temporary, as the returned pointer would be invalid
Command* get() && = delete;
/**
* Convert to the underlying unique_ptr.
*/
std::unique_ptr<Command> Unwrap() &&;
/**
* Schedules this command.
*
* @deprecated Use CommandScheduler::GetInstance().Schedule() instead
*/
[[deprecated("Use CommandScheduler::GetInstance().Schedule() instead.")]]
void Schedule() const&;
// Prevent calls on a temporary, as the returned pointer would be invalid
void Schedule() && = delete;
/**
* Cancels this command. Will call End(true). Commands will be canceled
* regardless of interruption behavior.
*/
void Cancel() const&;
// Prevent calls on a temporary, as the returned pointer would be invalid
void Cancel() && = delete;
/**
* Whether or not the command is currently scheduled. Note that this does not
* detect whether the command is in a composition, only whether it is directly
* being run by the scheduler.
*
* @return Whether the command is scheduled.
*/
bool IsScheduled() const&;
// Prevent calls on a temporary, as the returned pointer would be invalid
void IsScheduled() && = delete;
/**
* Whether the command requires a given subsystem. Named "HasRequirement"
* rather than "requires" to avoid confusion with Command::Requires(Subsystem)
* -- this may be able to be changed in a few years.
*
* @param requirement the subsystem to inquire about
* @return whether the subsystem is required
*/
bool HasRequirement(Subsystem* requirement) const&;
// Prevent calls on a temporary, as the returned pointer would be invalid
void HasRequirement(Subsystem* requirement) && = delete;
/**
* Check if this CommandPtr object is valid and wasn't moved-from.
*/
explicit operator bool() const&;
// Prevent calls on a temporary, as the returned pointer would be invalid
explicit operator bool() && = delete;
/**
* Convert a vector of CommandPtr objects to their underlying unique_ptrs.
*/
static std::vector<std::unique_ptr<Command>> UnwrapVector(
std::vector<CommandPtr>&& vec);
private:
std::unique_ptr<Command> m_ptr;
std::string m_moveOutSite{""};
void AssertValid() const;
};
} // namespace frc2

View File

@@ -0,0 +1,491 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#pragma once
#include <concepts>
#include <functional>
#include <initializer_list>
#include <memory>
#include <optional>
#include <span>
#include <utility>
#include <frc/Errors.h>
#include <frc/Watchdog.h>
#include <frc/event/EventLoop.h>
#include <units/time.h>
#include <wpi/FunctionExtras.h>
#include <wpi/sendable/Sendable.h>
#include <wpi/sendable/SendableHelper.h>
namespace frc2 {
class Command;
class CommandPtr;
class Subsystem;
/**
* The scheduler responsible for running Commands. A Command-based robot should
* call Run() on the singleton instance in its periodic block in order to run
* commands synchronously from the main loop. Subsystems should be registered
* with the scheduler using RegisterSubsystem() in order for their Periodic()
* methods to be called and for their default commands to be scheduled.
*
* This class is provided by the NewCommands VendorDep
*/
class CommandScheduler final : public wpi::Sendable,
public wpi::SendableHelper<CommandScheduler> {
public:
/**
* Returns the Scheduler instance.
*
* @return the instance
*/
static CommandScheduler& GetInstance();
~CommandScheduler() override;
CommandScheduler(const CommandScheduler&) = delete;
CommandScheduler& operator=(const CommandScheduler&) = delete;
using Action = std::function<void(const Command&)>;
using InterruptAction =
std::function<void(const Command&, const std::optional<Command*>&)>;
/**
* Changes the period of the loop overrun watchdog. This should be kept in
* sync with the TimedRobot period.
*/
void SetPeriod(units::second_t period);
/**
* Get the active button poll.
*
* @return a reference to the current {@link frc::EventLoop} object polling
* buttons.
*/
frc::EventLoop* GetActiveButtonLoop() const;
/**
* Replace the button poll with another one.
*
* @param loop the new button polling loop object.
*/
void SetActiveButtonLoop(frc::EventLoop* loop);
/**
* Get the default button poll.
*
* @return a reference to the default {@link frc::EventLoop} object polling
* buttons.
*/
frc::EventLoop* GetDefaultButtonLoop() const;
/**
* Schedules a command for execution. Does nothing if the command is already
* scheduled. If a command's requirements are not available, it will only be
* started if all the commands currently using those requirements are
* interruptible. If this is the case, they will be interrupted and the
* command will be scheduled.
*
* @warning Using this function directly can often lead to unexpected behavior
* and should be avoided. Instead Triggers should be used to schedule
* Commands.
*
* @param command the command to schedule
*/
void Schedule(const CommandPtr& command);
/**
* Schedules a command for execution. Does nothing if the command is already
* scheduled. If a command's requirements are not available, it will only be
* started if all the commands currently using those requirements are
* interruptible. If this is the case, they will be interrupted and the
* command will be scheduled.
*
* @param command the command to schedule
*/
void Schedule(CommandPtr&& command);
/**
* Schedules a command for execution. Does nothing if the command is already
* scheduled. If a command's requirements are not available, it will only be
* started if all the commands currently using those requirements have been
* scheduled as interruptible. If this is the case, they will be interrupted
* and the command will be scheduled.
*
* The pointer must remain valid through the entire lifecycle of the command.
*
* @warning Using this function directly can often lead to unexpected behavior
* and should be avoided. Instead Triggers should be used to schedule
* Commands.
*
* @param command the command to schedule
*/
void Schedule(Command* command);
/**
* Schedules multiple commands for execution. Does nothing for commands
* already scheduled.
*
* @warning Using this function directly can often lead to unexpected behavior
* and should be avoided. Instead Triggers should be used to schedule
* Commands.
*
* @param commands the commands to schedule
*/
void Schedule(std::span<Command* const> commands);
/**
* Schedules multiple commands for execution. Does nothing for commands
* already scheduled.
*
* @warning Using this function directly can often lead to unexpected behavior
* and should be avoided. Instead Triggers should be used to schedule
* Commands.
*
* @param commands the commands to schedule
*/
void Schedule(std::initializer_list<Command*> commands);
/**
* Runs a single iteration of the scheduler. The execution occurs in the
* following order:
*
* <p>Subsystem periodic methods are called.
*
* <p>Button bindings are polled, and new commands are scheduled from them.
*
* <p>Currently-scheduled commands are executed.
*
* <p>End conditions are checked on currently-scheduled commands, and commands
* that are finished have their end methods called and are removed.
*
* <p>Any subsystems not being used as requirements have their default methods
* started.
*/
void Run();
/**
* Registers subsystems with the scheduler. This must be called for the
* subsystem's periodic block to run when the scheduler is run, and for the
* subsystem's default command to be scheduled. It is recommended to call
* this from the constructor of your subsystem implementations.
*
* @param subsystem the subsystem to register
*/
void RegisterSubsystem(Subsystem* subsystem);
/**
* Un-registers subsystems with the scheduler. The subsystem will no longer
* have its periodic block called, and will not have its default command
* scheduled.
*
* @param subsystem the subsystem to un-register
*/
void UnregisterSubsystem(Subsystem* subsystem);
void RegisterSubsystem(std::initializer_list<Subsystem*> subsystems);
void RegisterSubsystem(std::span<Subsystem* const> subsystems);
void UnregisterSubsystem(std::initializer_list<Subsystem*> subsystems);
void UnregisterSubsystem(std::span<Subsystem* const> subsystems);
/**
* Un-registers all registered Subsystems with the scheduler. All currently
* registered subsystems will no longer have their periodic block called, and
* will not have their default command scheduled.
*/
void UnregisterAllSubsystems();
/**
* Sets the default command for a subsystem. Registers that subsystem if it
* is not already registered. Default commands will run whenever there is no
* other command currently scheduled that requires the subsystem. Default
* commands should be written to never end (i.e. their IsFinished() method
* should return false), as they would simply be re-scheduled if they do.
* Default commands must also require their subsystem.
*
* @param subsystem the subsystem whose default command will be set
* @param defaultCommand the default command to associate with the subsystem
*/
template <std::derived_from<Command> T>
void SetDefaultCommand(Subsystem* subsystem, T&& defaultCommand) {
if (!defaultCommand.HasRequirement(subsystem)) {
throw FRC_MakeError(frc::err::CommandIllegalUse,
"Default commands must require their subsystem!");
}
SetDefaultCommandImpl(subsystem, std::make_unique<std::decay_t<T>>(
std::forward<T>(defaultCommand)));
}
/**
* Sets the default command for a subsystem. Registers that subsystem if it
* is not already registered. Default commands will run whenever there is no
* other command currently scheduled that requires the subsystem. Default
* commands should be written to never end (i.e. their IsFinished() method
* should return false), as they would simply be re-scheduled if they do.
* Default commands must also require their subsystem.
*
* @param subsystem the subsystem whose default command will be set
* @param defaultCommand the default command to associate with the subsystem
*/
void SetDefaultCommand(Subsystem* subsystem, CommandPtr&& defaultCommand);
/**
* Removes the default command for a subsystem. The current default command
* will run until another command is scheduled that requires the subsystem, at
* which point the current default command will not be re-scheduled.
*
* @param subsystem the subsystem whose default command will be removed
*/
void RemoveDefaultCommand(Subsystem* subsystem);
/**
* Gets the default command associated with this subsystem. Null if this
* subsystem has no default command associated with it.
*
* @param subsystem the subsystem to inquire about
* @return the default command associated with the subsystem
*/
Command* GetDefaultCommand(const Subsystem* subsystem) const;
/**
* Cancels commands. The scheduler will only call Command::End()
* method of the canceled command with true, indicating they were
* canceled (as opposed to finishing normally).
*
* <p>Commands will be canceled even if they are not scheduled as
* interruptible.
*
* @param command the command to cancel
*/
void Cancel(Command* command);
/**
* Cancels commands. The scheduler will only call Command::End()
* method of the canceled command with true, indicating they were
* canceled (as opposed to finishing normally).
*
* <p>Commands will be canceled even if they are not scheduled as
* interruptible.
*
* @param command the command to cancel
*/
void Cancel(const CommandPtr& command);
/**
* Cancels commands. The scheduler will only call Command::End()
* method of the canceled command with true, indicating they were
* canceled (as opposed to finishing normally).
*
* <p>Commands will be canceled even if they are not scheduled as
* interruptible.
*
* @param commands the commands to cancel
*/
void Cancel(std::span<Command* const> commands);
/**
* Cancels commands. The scheduler will only call Command::End()
* method of the canceled command with true, indicating they were
* canceled (as opposed to finishing normally).
*
* <p>Commands will be canceled even if they are not scheduled as
* interruptible.
*
* @param commands the commands to cancel
*/
void Cancel(std::initializer_list<Command*> commands);
/**
* Cancels all commands that are currently scheduled.
*/
void CancelAll();
/**
* Whether the given commands are running. Note that this only works on
* commands that are directly scheduled by the scheduler; it will not work on
* commands inside of CommandGroups, as the scheduler does not see them.
*
* @param commands the command to query
* @return whether the command is currently scheduled
*/
bool IsScheduled(std::span<const Command* const> commands) const;
/**
* Whether the given commands are running. Note that this only works on
* commands that are directly scheduled by the scheduler; it will not work on
* commands inside of CommandGroups, as the scheduler does not see them.
*
* @param commands the command to query
* @return whether the command is currently scheduled
*/
bool IsScheduled(std::initializer_list<const Command*> commands) const;
/**
* Whether a given command is running. Note that this only works on commands
* that are directly scheduled by the scheduler; it will not work on commands
* inside of CommandGroups, as the scheduler does not see them.
*
* @param command the command to query
* @return whether the command is currently scheduled
*/
bool IsScheduled(const Command* command) const;
/**
* Whether a given command is running. Note that this only works on commands
* that are directly scheduled by the scheduler; it will not work on commands
* inside of CommandGroups, as the scheduler does not see them.
*
* @param command the command to query
* @return whether the command is currently scheduled
*/
bool IsScheduled(const CommandPtr& command) const;
/**
* Returns the command currently requiring a given subsystem. Null if no
* command is currently requiring the subsystem
*
* @param subsystem the subsystem to be inquired about
* @return the command currently requiring the subsystem
*/
Command* Requiring(const Subsystem* subsystem) const;
/**
* Disables the command scheduler.
*/
void Disable();
/**
* Enables the command scheduler.
*/
void Enable();
/**
* Prints list of epochs added so far and their times.
*/
void PrintWatchdogEpochs();
/**
* Adds an action to perform on the initialization of any command by the
* scheduler.
*
* @param action the action to perform
*/
void OnCommandInitialize(Action action);
/**
* Adds an action to perform on the execution of any command by the scheduler.
*
* @param action the action to perform
*/
void OnCommandExecute(Action action);
/**
* Adds an action to perform on the interruption of any command by the
* scheduler.
*
* @param action the action to perform
*/
void OnCommandInterrupt(Action action);
/**
* Adds an action to perform on the interruption of any command by the
* scheduler. The action receives the interrupted command and an optional
* containing the interrupting command, or nullopt if it was not canceled by a
* command (e.g., by Cancel()).
*
* @param action the action to perform
*/
void OnCommandInterrupt(InterruptAction action);
/**
* Adds an action to perform on the finishing of any command by the scheduler.
*
* @param action the action to perform
*/
void OnCommandFinish(Action action);
/**
* Requires that the specified command hasn't already been added to a
* composition.
*
* @param command The command to check
* @throws if the given commands have already been composed.
*/
void RequireUngrouped(const Command* command);
/**
* Requires that the specified commands have not already been added to a
* composition.
*
* @param commands The commands to check
* @throws if the given commands have already been composed.
*/
void RequireUngrouped(std::span<const std::unique_ptr<Command>> commands);
/**
* Requires that the specified commands have not already been added to a
* composition.
*
* @param commands The commands to check
* @throws IllegalArgumentException if the given commands have already been
* composed.
*/
void RequireUngrouped(std::initializer_list<const Command*> commands);
/**
* Requires that the specified command has not already been added to a
* composition and is not currently scheduled.
*
* @param command The command to check
* @throws IllegalArgumentException if the given command has already been
* composed or scheduled.
*/
void RequireUngroupedAndUnscheduled(const Command* command);
/**
* Requires that the specified commands have not already been added to a
* composition and are not currently scheduled.
*
* @param commands The commands to check
* @throws IllegalArgumentException if the given commands have already been
* composed.
*/
void RequireUngroupedAndUnscheduled(
std::span<const std::unique_ptr<Command>> commands);
/**
* Requires that the specified commands have not already been added to a
* composition and are not currently scheduled.
*
* @param commands The commands to check
* @throws IllegalArgumentException if the given commands have already been
* composed or scheduled.
*/
void RequireUngroupedAndUnscheduled(
std::initializer_list<const Command*> commands);
void InitSendable(wpi::SendableBuilder& builder) override;
private:
// Constructor; private as this is a singleton
CommandScheduler();
void SetDefaultCommandImpl(Subsystem* subsystem,
std::unique_ptr<Command> command);
void Cancel(Command* command, std::optional<Command*> interruptor);
class Impl;
std::unique_ptr<Impl> m_impl;
frc::Watchdog m_watchdog;
friend class CommandTestBase;
template <typename T>
friend class CommandTestBaseWithParam;
};
} // namespace frc2

View File

@@ -0,0 +1,267 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#pragma once
#include <concepts>
#include <functional>
#include <memory>
#include <string>
#include <type_traits>
#include <utility>
#include <vector>
#include <wpi/deprecated.h>
#include "frc2/command/CommandPtr.h"
#include "frc2/command/Requirements.h"
#include "frc2/command/SelectCommand.h"
namespace frc2 {
class Subsystem;
/**
* Namespace for command factories.
*/
namespace cmd {
/**
* Constructs a command that does nothing, finishing immediately.
*/
CommandPtr None();
/**
* Constructs a command that does nothing until interrupted.
*
* @param requirements Subsystems to require
* @return the command
*/
CommandPtr Idle(Requirements requirements = {});
// Action Commands
/**
* Constructs a command that runs an action once and finishes.
*
* @param action the action to run
* @param requirements subsystems the action requires
*/
CommandPtr RunOnce(std::function<void()> action,
Requirements requirements = {});
/**
* Constructs a command that runs an action every iteration until interrupted.
*
* @param action the action to run
* @param requirements subsystems the action requires
*/
CommandPtr Run(std::function<void()> action, Requirements requirements = {});
/**
* Constructs a command that runs an action once and another action when the
* command is interrupted.
*
* @param start the action to run on start
* @param end the action to run on interrupt
* @param requirements subsystems the action requires
*/
CommandPtr StartEnd(std::function<void()> start, std::function<void()> end,
Requirements requirements = {});
/**
* Constructs a command that runs an action every iteration until interrupted,
* and then runs a second action.
*
* @param run the action to run every iteration
* @param end the action to run on interrupt
* @param requirements subsystems the action requires
*/
CommandPtr RunEnd(std::function<void()> run, std::function<void()> end,
Requirements requirements = {});
/**
* Constructs a command that runs an action once, and then runs an action every
* iteration until interrupted.
*
* @param start the action to run on start
* @param run the action to run every iteration
* @param requirements subsystems the action requires
*/
CommandPtr StartRun(std::function<void()> start, std::function<void()> run,
Requirements requirements = {});
/**
* Constructs a command that prints a message and finishes.
*
* @param msg the message to print
*/
CommandPtr Print(std::string_view msg);
// Idling Commands
/**
* Constructs a command that does nothing, finishing after a specified duration.
*
* @param duration after how long the command finishes
*/
CommandPtr Wait(units::second_t duration);
/**
* Constructs a command that does nothing, finishing once a condition becomes
* true.
*
* @param condition the condition
*/
CommandPtr WaitUntil(std::function<bool()> condition);
// Selector Commands
/**
* Runs one of two commands, based on the boolean selector function.
*
* @param onTrue the command to run if the selector function returns true
* @param onFalse the command to run if the selector function returns false
* @param selector the selector function
*/
CommandPtr Either(CommandPtr&& onTrue, CommandPtr&& onFalse,
std::function<bool()> selector);
/**
* Runs one of several commands, based on the selector function.
*
* @param selector the selector function
* @param commands map of commands to select from
*/
template <typename Key, std::convertible_to<CommandPtr>... CommandPtrs>
CommandPtr Select(std::function<Key()> selector,
std::pair<Key, CommandPtrs>&&... commands) {
std::vector<std::pair<Key, std::unique_ptr<Command>>> vec;
((void)vec.emplace_back(commands.first, std::move(commands.second).Unwrap()),
...);
return SelectCommand(std::move(selector), std::move(vec)).ToPtr();
}
/**
* Runs the command supplied by the supplier.
*
* @param supplier the command supplier
* @param requirements the set of requirements for this command
*/
CommandPtr Defer(wpi::unique_function<CommandPtr()> supplier,
Requirements requirements);
/**
* Constructs a command that schedules the command returned from the supplier
* when initialized, and ends when it is no longer scheduled. The supplier is
* called when the command is initialized.
*
* @param supplier the command supplier
*/
CommandPtr DeferredProxy(wpi::unique_function<Command*()> supplier);
/**
* Constructs a command that schedules the command returned from the supplier
* when initialized, and ends when it is no longer scheduled. The supplier is
* called when the command is initialized.
*
* @param supplier the command supplier
*/
CommandPtr DeferredProxy(wpi::unique_function<CommandPtr()> supplier);
// Command Groups
namespace impl {
/**
* Create a vector of commands.
*/
template <std::convertible_to<CommandPtr>... Args>
std::vector<CommandPtr> MakeVector(Args&&... args) {
std::vector<CommandPtr> data;
data.reserve(sizeof...(Args));
(data.emplace_back(std::forward<Args>(args)), ...);
return data;
}
} // namespace impl
/**
* Runs a group of commands in series, one after the other.
*/
CommandPtr Sequence(std::vector<CommandPtr>&& commands);
/**
* Runs a group of commands in series, one after the other.
*/
template <std::convertible_to<CommandPtr>... CommandPtrs>
CommandPtr Sequence(CommandPtrs&&... commands) {
return Sequence(impl::MakeVector(std::forward<CommandPtrs>(commands)...));
}
/**
* Runs a group of commands in series, one after the other. Once the last
* command ends, the group is restarted.
*/
CommandPtr RepeatingSequence(std::vector<CommandPtr>&& commands);
/**
* Runs a group of commands in series, one after the other. Once the last
* command ends, the group is restarted.
*/
template <std::convertible_to<CommandPtr>... CommandPtrs>
CommandPtr RepeatingSequence(CommandPtrs&&... commands) {
return RepeatingSequence(
impl::MakeVector(std::forward<CommandPtrs>(commands)...));
}
/**
* Runs a group of commands at the same time. Ends once all commands in the
* group finish.
*/
CommandPtr Parallel(std::vector<CommandPtr>&& commands);
/**
* Runs a group of commands at the same time. Ends once all commands in the
* group finish.
*/
template <std::convertible_to<CommandPtr>... CommandPtrs>
CommandPtr Parallel(CommandPtrs&&... commands) {
return Parallel(impl::MakeVector(std::forward<CommandPtrs>(commands)...));
}
/**
* Runs a group of commands at the same time. Ends once any command in the group
* finishes, and cancels the others.
*/
CommandPtr Race(std::vector<CommandPtr>&& commands);
/**
* Runs a group of commands at the same time. Ends once any command in the group
* finishes, and cancels the others.
*/
template <std::convertible_to<CommandPtr>... CommandPtrs>
CommandPtr Race(CommandPtrs&&... commands) {
return Race(impl::MakeVector(std::forward<CommandPtrs>(commands)...));
}
/**
* Runs a group of commands at the same time. Ends once a specific command
* finishes, and cancels the others.
*/
CommandPtr Deadline(CommandPtr&& deadline, std::vector<CommandPtr>&& others);
/**
* Runs a group of commands at the same time. Ends once a specific command
* finishes, and cancels the others.
*/
template <std::convertible_to<CommandPtr>... CommandPtrs>
CommandPtr Deadline(CommandPtr&& deadline, CommandPtrs&&... commands) {
return Deadline(std::move(deadline),
impl::MakeVector(std::forward<CommandPtrs>(commands)...));
}
} // namespace cmd
} // namespace frc2

View File

@@ -0,0 +1,85 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#pragma once
#include <concepts>
#include <functional>
#include <memory>
#include <utility>
#include "frc2/command/Command.h"
#include "frc2/command/CommandHelper.h"
namespace frc2 {
/**
* A command composition that runs one of two commands, depending on the value
* of the given condition when this command is initialized.
*
* <p>The rules for command compositions apply: command instances that are
* passed to it are owned by the composition and cannot be added to any other
* composition or scheduled individually, and the composition requires all
* subsystems its components require.
*
* This class is provided by the NewCommands VendorDep
*
* @see ScheduleCommand
*/
class ConditionalCommand : public CommandHelper<Command, ConditionalCommand> {
public:
/**
* Creates a new ConditionalCommand.
*
* @param onTrue the command to run if the condition is true
* @param onFalse the command to run if the condition is false
* @param condition the condition to determine which command to run
*/
template <std::derived_from<Command> Command1,
std::derived_from<Command> Command2>
ConditionalCommand(Command1&& onTrue, Command2&& onFalse,
std::function<bool()> condition)
: ConditionalCommand(std::make_unique<std::decay_t<Command1>>(
std::forward<Command1>(onTrue)),
std::make_unique<std::decay_t<Command2>>(
std::forward<Command2>(onFalse)),
condition) {}
/**
* Creates a new ConditionalCommand.
*
* @param onTrue the command to run if the condition is true
* @param onFalse the command to run if the condition is false
* @param condition the condition to determine which command to run
*/
ConditionalCommand(std::unique_ptr<Command>&& onTrue,
std::unique_ptr<Command>&& onFalse,
std::function<bool()> condition);
ConditionalCommand(ConditionalCommand&& other) = default;
// No copy constructors for command groups
ConditionalCommand(const ConditionalCommand& other) = delete;
void Initialize() override;
void Execute() override;
void End(bool interrupted) override;
bool IsFinished() override;
bool RunsWhenDisabled() const override;
InterruptionBehavior GetInterruptionBehavior() const override;
void InitSendable(wpi::SendableBuilder& builder) override;
private:
std::unique_ptr<Command> m_onTrue;
std::unique_ptr<Command> m_onFalse;
std::function<bool()> m_condition;
Command* m_selectedCommand{nullptr};
bool m_runsWhenDisabled = true;
};
} // namespace frc2

View File

@@ -0,0 +1,60 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#pragma once
#include <memory>
#include <wpi/FunctionExtras.h>
#include "frc2/command/Command.h"
#include "frc2/command/CommandHelper.h"
#include "frc2/command/Requirements.h"
namespace frc2 {
/**
* Defers Command construction to runtime. Runs the command returned by a
* supplier when this command is initialized, and ends when it ends. Useful for
* performing runtime tasks before creating a new command. If this command is
* interrupted, it will cancel the command.
*
* Note that the supplier <i>must</i> create a new Command each call. For
* selecting one of a preallocated set of commands, use SelectCommand.
*
* <p>This class is provided by the NewCommands VendorDep
*/
class DeferredCommand : public CommandHelper<Command, DeferredCommand> {
public:
/**
* Creates a new DeferredCommand that directly runs the supplied command when
* initialized, and ends when it ends. Useful for lazily creating commands
* when the DeferredCommand is initialized, such as if the supplied command
* depends on runtime state. The supplier will be called each time this
* command is initialized. The supplier <i>must</i> create a new Command each
* call.
*
* @param supplier The command supplier
* @param requirements The command requirements.
*
*/
DeferredCommand(wpi::unique_function<CommandPtr()> supplier,
Requirements requirements);
DeferredCommand(DeferredCommand&& other) = default;
void Initialize() override;
void Execute() override;
void End(bool interrupted) override;
bool IsFinished() override;
void InitSendable(wpi::SendableBuilder& builder) override;
private:
wpi::unique_function<CommandPtr()> m_supplier;
std::unique_ptr<Command> m_command;
};
} // namespace frc2

View File

@@ -0,0 +1,59 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#pragma once
#include <functional>
#include "frc2/command/Command.h"
#include "frc2/command/CommandHelper.h"
#include "frc2/command/Requirements.h"
namespace frc2 {
/**
* A command that allows the user to pass in functions for each of the basic
* command methods through the constructor. Useful for inline definitions of
* complex commands - note, however, that if a command is beyond a certain
* complexity it is usually better practice to write a proper class for it than
* to inline it.
*
* This class is provided by the NewCommands VendorDep
*/
class FunctionalCommand : public CommandHelper<Command, FunctionalCommand> {
public:
/**
* Creates a new FunctionalCommand.
*
* @param onInit the function to run on command initialization
* @param onExecute the function to run on command execution
* @param onEnd the function to run on command end
* @param isFinished the function that determines whether the command has
* finished
* @param requirements the subsystems required by this command
*/
FunctionalCommand(std::function<void()> onInit,
std::function<void()> onExecute,
std::function<void(bool)> onEnd,
std::function<bool()> isFinished,
Requirements requirements = {});
FunctionalCommand(FunctionalCommand&& other) = default;
FunctionalCommand(const FunctionalCommand& other) = default;
void Initialize() override;
void Execute() override;
void End(bool interrupted) override;
bool IsFinished() override;
private:
std::function<void()> m_onInit;
std::function<void()> m_onExecute;
std::function<void(bool)> m_onEnd;
std::function<bool()> m_isFinished;
};
} // namespace frc2

View File

@@ -0,0 +1,43 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#pragma once
#include <functional>
#include "frc2/command/CommandHelper.h"
#include "frc2/command/FunctionalCommand.h"
#include "frc2/command/Requirements.h"
namespace frc2 {
/**
* A Command that runs instantly; it will initialize, execute once, and end on
* the same iteration of the scheduler. Users can either pass in a Runnable and
* a set of requirements, or else subclass this command if desired.
*
* This class is provided by the NewCommands VendorDep
*/
class InstantCommand : public CommandHelper<FunctionalCommand, InstantCommand> {
public:
/**
* Creates a new InstantCommand that runs the given Runnable with the given
* requirements.
*
* @param toRun the Runnable to run
* @param requirements the subsystems required by this command
*/
explicit InstantCommand(std::function<void()> toRun,
Requirements requirements = {});
InstantCommand(InstantCommand&& other) = default;
InstantCommand(const InstantCommand& other) = default;
/**
* Creates a new InstantCommand with a Runnable that does nothing. Useful
* only as a no-arg constructor to call implicitly from subclass constructors.
*/
InstantCommand();
};
} // namespace frc2

View File

@@ -0,0 +1,54 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#pragma once
#include <functional>
#include <frc/Notifier.h>
#include <units/time.h>
#include "frc2/command/Command.h"
#include "frc2/command/CommandHelper.h"
#include "frc2/command/Requirements.h"
namespace frc2 {
/**
* A command that starts a notifier to run the given runnable periodically in a
* separate thread. Has no end condition as-is; either subclass it or use
* Command::WithTimeout(double) or Command::Until(BooleanSupplier) to
* give it one.
*
* <p>WARNING: Do not use this class unless you are confident in your ability to
* make the executed code thread-safe. If you do not know what "thread-safe"
* means, that is a good sign that you should not use this class.
*
* This class is provided by the NewCommands VendorDep
*/
class NotifierCommand : public CommandHelper<Command, NotifierCommand> {
public:
/**
* Creates a new NotifierCommand.
*
* @param toRun the runnable for the notifier to run
* @param period the period at which the notifier should run
* @param requirements the subsystems required by this command
*/
NotifierCommand(std::function<void()> toRun, units::second_t period,
Requirements requirements = {});
NotifierCommand(NotifierCommand&& other);
NotifierCommand(const NotifierCommand& other);
void Initialize() override;
void End(bool interrupted) override;
private:
std::function<void()> m_toRun;
frc::Notifier m_notifier;
units::second_t m_period;
};
} // namespace frc2

View File

@@ -0,0 +1,107 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#pragma once
#ifdef _WIN32
#pragma warning(push)
#pragma warning(disable : 4521)
#endif
#include <memory>
#include <type_traits>
#include <utility>
#include <vector>
#include <wpi/DecayedDerivedFrom.h>
#include "frc2/command/CommandHelper.h"
namespace frc2 {
/**
* A command composition that runs a set of commands in parallel, ending when
* the last command ends.
*
* <p>The rules for command compositions apply: command instances that are
* passed to it are owned by the composition and cannot be added to any other
* composition or scheduled individually, and the composition requires all
* subsystems its components require.
*
* This class is provided by the NewCommands VendorDep
*/
class ParallelCommandGroup
: public CommandHelper<Command, ParallelCommandGroup> {
public:
/**
* Creates a new ParallelCommandGroup. The given commands will be executed
* simultaneously. The command group will finish when the last command
* finishes. If the composition is interrupted, only the commands that are
* still running will be interrupted.
*
* @param commands the commands to include in this composition.
*/
explicit ParallelCommandGroup(
std::vector<std::unique_ptr<Command>>&& commands);
/**
* Creates a new ParallelCommandGroup. The given commands will be executed
* simultaneously. The command group will finish when the last command
* finishes. If the composition is interrupted, only the commands that are
* still running will be interrupted.
*
* @param commands the commands to include in this composition.
*/
template <wpi::DecayedDerivedFrom<Command>... Commands>
explicit ParallelCommandGroup(Commands&&... commands) {
AddCommands(std::forward<Commands>(commands)...);
}
ParallelCommandGroup(ParallelCommandGroup&& other) = default;
// No copy constructors for command groups
ParallelCommandGroup(const ParallelCommandGroup&) = delete;
// Prevent template expansion from emulating copy ctor
ParallelCommandGroup(ParallelCommandGroup&) = delete;
/**
* Adds the given commands to the group.
*
* @param commands Commands to add to the group.
*/
template <wpi::DecayedDerivedFrom<Command>... Commands>
void AddCommands(Commands&&... commands) {
std::vector<std::unique_ptr<Command>> foo;
((void)foo.emplace_back(std::make_unique<std::decay_t<Commands>>(
std::forward<Commands>(commands))),
...);
AddCommands(std::move(foo));
}
void Initialize() final;
void Execute() final;
void End(bool interrupted) final;
bool IsFinished() final;
bool RunsWhenDisabled() const override;
Command::InterruptionBehavior GetInterruptionBehavior() const override;
private:
void AddCommands(std::vector<std::unique_ptr<Command>>&& commands);
std::vector<std::pair<std::unique_ptr<Command>, bool>> m_commands;
bool m_runWhenDisabled{true};
Command::InterruptionBehavior m_interruptBehavior{
Command::InterruptionBehavior::kCancelIncoming};
bool isRunning = false;
};
} // namespace frc2
#ifdef _WIN32
#pragma warning(pop)
#endif

View File

@@ -0,0 +1,118 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#pragma once
#ifdef _WIN32
#pragma warning(push)
#pragma warning(disable : 4521)
#endif
#include <memory>
#include <type_traits>
#include <utility>
#include <vector>
#include <wpi/DecayedDerivedFrom.h>
#include "frc2/command/CommandHelper.h"
namespace frc2 {
/**
* A command composition that runs a set of commands in parallel, ending only
* when a specific command (the "deadline") ends, interrupting all other
* commands that are still running at that point.
*
* <p>The rules for command compositions apply: command instances that are
* passed to it are owned by the composition and cannot be added to any other
* composition or scheduled individually, and the composition requires all
* subsystems its components require.
*
* This class is provided by the NewCommands VendorDep
*/
class ParallelDeadlineGroup
: public CommandHelper<Command, ParallelDeadlineGroup> {
public:
/**
* Creates a new ParallelDeadlineGroup. The given commands (including the
* deadline) will be executed simultaneously. The composition will finish when
* the deadline finishes, interrupting all other still-running commands. If
* the composition is interrupted, only the commands still running will be
* interrupted.
*
* @param deadline the command that determines when the composition ends
* @param commands the commands to be executed
*/
ParallelDeadlineGroup(std::unique_ptr<Command>&& deadline,
std::vector<std::unique_ptr<Command>>&& commands);
/**
* Creates a new ParallelDeadlineGroup. The given commands (including the
* deadline) will be executed simultaneously. The composition will finish when
* the deadline finishes, interrupting all other still-running commands. If
* the composition is interrupted, only the commands still running will be
* interrupted.
*
* @param deadline the command that determines when the composition ends
* @param commands the commands to be executed
*/
template <wpi::DecayedDerivedFrom<Command> T,
wpi::DecayedDerivedFrom<Command>... Commands>
explicit ParallelDeadlineGroup(T&& deadline, Commands&&... commands) {
SetDeadline(std::make_unique<std::decay_t<T>>(std::forward<T>(deadline)));
AddCommands(std::forward<Commands>(commands)...);
}
ParallelDeadlineGroup(ParallelDeadlineGroup&& other) = default;
// No copy constructors for command groups
ParallelDeadlineGroup(const ParallelDeadlineGroup&) = delete;
// Prevent template expansion from emulating copy ctor
ParallelDeadlineGroup(ParallelDeadlineGroup&) = delete;
/**
* Adds the given commands to the group.
*
* @param commands Commands to add to the group.
*/
template <wpi::DecayedDerivedFrom<Command>... Commands>
void AddCommands(Commands&&... commands) {
std::vector<std::unique_ptr<Command>> foo;
((void)foo.emplace_back(std::make_unique<std::decay_t<Commands>>(
std::forward<Commands>(commands))),
...);
AddCommands(std::move(foo));
}
void Initialize() final;
void Execute() final;
void End(bool interrupted) final;
bool IsFinished() final;
bool RunsWhenDisabled() const override;
Command::InterruptionBehavior GetInterruptionBehavior() const override;
void InitSendable(wpi::SendableBuilder& builder) override;
private:
void AddCommands(std::vector<std::unique_ptr<Command>>&& commands);
void SetDeadline(std::unique_ptr<Command>&& deadline);
std::vector<std::pair<std::unique_ptr<Command>, bool>> m_commands;
Command* m_deadline;
bool m_runWhenDisabled{true};
Command::InterruptionBehavior m_interruptBehavior{
Command::InterruptionBehavior::kCancelIncoming};
bool m_finished{true};
};
} // namespace frc2
#ifdef _WIN32
#pragma warning(pop)
#endif

View File

@@ -0,0 +1,97 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#pragma once
#ifdef _WIN32
#pragma warning(push)
#pragma warning(disable : 4521)
#endif
#include <memory>
#include <type_traits>
#include <utility>
#include <vector>
#include <wpi/DecayedDerivedFrom.h>
#include "frc2/command/CommandHelper.h"
namespace frc2 {
/**
* A composition that runs a set of commands in parallel, ending when any one of
* the commands ends and interrupting all the others.
*
* <p>The rules for command compositions apply: command instances that are
* passed to it are owned by the composition and cannot be added to any other
* composition or scheduled individually, and the composition requires all
* subsystems its components require.
*
* This class is provided by the NewCommands VendorDep
*/
class ParallelRaceGroup : public CommandHelper<Command, ParallelRaceGroup> {
public:
/**
* Creates a new ParallelCommandRace. The given commands will be executed
* simultaneously, and will "race to the finish" - the first command to finish
* ends the entire command, with all other commands being interrupted.
*
* @param commands the commands to include in this composition.
*/
explicit ParallelRaceGroup(std::vector<std::unique_ptr<Command>>&& commands);
template <wpi::DecayedDerivedFrom<Command>... Commands>
explicit ParallelRaceGroup(Commands&&... commands) {
AddCommands(std::forward<Commands>(commands)...);
}
ParallelRaceGroup(ParallelRaceGroup&& other) = default;
// No copy constructors for command groups
ParallelRaceGroup(const ParallelRaceGroup&) = delete;
// Prevent template expansion from emulating copy ctor
ParallelRaceGroup(ParallelRaceGroup&) = delete;
/**
* Adds the given commands to the group.
*
* @param commands Commands to add to the group.
*/
template <wpi::DecayedDerivedFrom<Command>... Commands>
void AddCommands(Commands&&... commands) {
std::vector<std::unique_ptr<Command>> foo;
((void)foo.emplace_back(std::make_unique<std::decay_t<Commands>>(
std::forward<Commands>(commands))),
...);
AddCommands(std::move(foo));
}
void Initialize() final;
void Execute() final;
void End(bool interrupted) final;
bool IsFinished() final;
bool RunsWhenDisabled() const override;
Command::InterruptionBehavior GetInterruptionBehavior() const override;
private:
void AddCommands(std::vector<std::unique_ptr<Command>>&& commands);
std::vector<std::unique_ptr<Command>> m_commands;
bool m_runWhenDisabled{true};
Command::InterruptionBehavior m_interruptBehavior{
Command::InterruptionBehavior::kCancelIncoming};
bool m_finished{false};
bool isRunning = false;
};
} // namespace frc2
#ifdef _WIN32
#pragma warning(pop)
#endif

View File

@@ -0,0 +1,33 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#pragma once
#include <string_view>
#include "frc2/command/CommandHelper.h"
#include "frc2/command/InstantCommand.h"
namespace frc2 {
/**
* A command that prints a string when initialized.
*
* This class is provided by the NewCommands VendorDep
*/
class PrintCommand : public CommandHelper<InstantCommand, PrintCommand> {
public:
/**
* Creates a new a PrintCommand.
*
* @param message the message to print
*/
explicit PrintCommand(std::string_view message);
PrintCommand(PrintCommand&& other) = default;
PrintCommand(const PrintCommand& other) = default;
bool RunsWhenDisabled() const override;
};
} // namespace frc2

View File

@@ -0,0 +1,104 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#pragma once
#include <memory>
#include <wpi/FunctionExtras.h>
#include <wpi/deprecated.h>
#include "frc2/command/Command.h"
#include "frc2/command/CommandHelper.h"
namespace frc2 {
/**
* Schedules a given command when this command is initialized and ends when it
* ends, but does not directly run it. Use this for including a command in a
* composition without adding its requirements, <strong>but only if you know
* what you are doing. If you are unsure, see <a
* href="https://docs.wpilib.org/en/stable/docs/software/commandbased/command-compositions.html#scheduling-other-commands">the
* WPILib docs</a> for a complete explanation of proxy semantics.</strong> Do
* not proxy a command from a subsystem already required by the composition, or
* else the composition will cancel itself when the proxy is reached. If this
* command is interrupted, it will cancel the command.
*
* <p>This class is provided by the NewCommands VendorDep
*/
class ProxyCommand : public CommandHelper<Command, ProxyCommand> {
public:
/**
* Creates a new ProxyCommand that schedules the supplied command when
* initialized, and ends when it is no longer scheduled. Use this for lazily
* creating <strong>proxied</strong> commands at runtime. Proxying should only
* be done to escape from composition requirement semantics, so if only
* initialization time command construction is needed, use {@link
* DeferredCommand} instead.
*
* @param supplier the command supplier
* @deprecated This constructor's similarity to {@link DeferredCommand} is
* confusing and opens potential footguns for users who do not fully
* understand the semantics and implications of proxying, but who simply want
* runtime construction. Users who do know what they are doing and need a
* supplier-constructed proxied command should instead defer a proxy command.
* @see DeferredCommand
*/
WPI_IGNORE_DEPRECATED
[[deprecated("Defer a proxy command instead.")]]
explicit ProxyCommand(wpi::unique_function<Command*()> supplier);
/**
* Creates a new ProxyCommand that schedules the supplied command when
* initialized, and ends when it is no longer scheduled. Use this for lazily
* creating <strong>proxied</strong> commands at runtime. Proxying should only
* be done to escape from composition requirement semantics, so if only
* initialization time command construction is needed, use {@link
* DeferredCommand} instead.
*
* @param supplier the command supplier
* @deprecated This constructor's similarity to {@link DeferredCommand} is
* confusing and opens potential footguns for users who do not fully
* understand the semantics and implications of proxying, but who simply want
* runtime construction. Users who do know what they are doing and need a
* supplier-constructed proxied command should instead defer a proxy command.
* @see DeferredCommand
*/
[[deprecated("Defer a proxy command instead.")]]
explicit ProxyCommand(wpi::unique_function<CommandPtr()> supplier);
WPI_UNIGNORE_DEPRECATED
/**
* Creates a new ProxyCommand that schedules the given command when
* initialized, and ends when it is no longer scheduled.
*
* @param command the command to run by proxy
*/
explicit ProxyCommand(Command* command);
/**
* Creates a new ProxyCommand that schedules the given command when
* initialized, and ends when it is no longer scheduled.
*
* <p>Note that this constructor passes ownership of the given command to the
* returned ProxyCommand.
*
* @param command the command to schedule
*/
explicit ProxyCommand(std::unique_ptr<Command> command);
ProxyCommand(ProxyCommand&& other) = default;
void Initialize() override;
void End(bool interrupted) override;
bool IsFinished() override;
void InitSendable(wpi::SendableBuilder& builder) override;
private:
wpi::unique_function<Command*()> m_supplier;
Command* m_command = nullptr;
};
} // namespace frc2

View File

@@ -0,0 +1,84 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#pragma once
#ifdef _WIN32
#pragma warning(push)
#pragma warning(disable : 4521)
#endif
#include <concepts>
#include <memory>
#include <utility>
#include "frc2/command/Command.h"
#include "frc2/command/CommandHelper.h"
namespace frc2 {
/**
* A command that runs another command repeatedly, restarting it when it ends,
* until this command is interrupted. Command instances that are passed to it
* cannot be added to any other groups, or scheduled individually.
*
* <p>The rules for command compositions apply: command instances that are
* passed to it are owned by the composition and cannot be added to any other
* composition or scheduled individually, and the composition requires all
* subsystems its components require.
*
* <p>This class is provided by the NewCommands VendorDep
*/
class RepeatCommand : public CommandHelper<Command, RepeatCommand> {
public:
/**
* Creates a new RepeatCommand. Will run another command repeatedly,
* restarting it whenever it ends, until this command is interrupted.
*
* @param command the command to run repeatedly
*/
explicit RepeatCommand(std::unique_ptr<Command>&& command);
/**
* Creates a new RepeatCommand. Will run another command repeatedly,
* restarting it whenever it ends, until this command is interrupted.
*
* @param command the command to run repeatedly
*/
template <std::derived_from<Command> T>
// NOLINTNEXTLINE(bugprone-forwarding-reference-overload)
explicit RepeatCommand(T&& command)
: RepeatCommand(
std::make_unique<std::decay_t<T>>(std::forward<T>(command))) {}
RepeatCommand(RepeatCommand&& other) = default;
// No copy constructors for command groups
RepeatCommand(const RepeatCommand& other) = delete;
// Prevent template expansion from emulating copy ctor
RepeatCommand(RepeatCommand&) = delete;
void Initialize() override;
void Execute() override;
bool IsFinished() override;
void End(bool interrupted) override;
bool RunsWhenDisabled() const override;
Command::InterruptionBehavior GetInterruptionBehavior() const override;
void InitSendable(wpi::SendableBuilder& builder) override;
private:
std::unique_ptr<Command> m_command;
bool m_ended;
};
} // namespace frc2
#ifdef _WIN32
#pragma warning(pop)
#endif

View File

@@ -0,0 +1,46 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#pragma once
#include <initializer_list>
#include <span>
#include <vector>
#include "frc2/command/Subsystem.h"
namespace frc2 {
/**
* Represents requirements for a command, which is a set of (pointers to)
* subsystems. This class is implicitly convertible from std::initializer_list
* and std::span.
*/
class Requirements {
public:
// NOLINTNEXTLINE
/*implicit*/ Requirements(std::initializer_list<Subsystem*> requirements)
: m_subsystems{requirements.begin(), requirements.end()} {}
// NOLINTNEXTLINE
/*implicit*/ Requirements(std::span<Subsystem* const> requirements)
: m_subsystems{requirements.begin(), requirements.end()} {}
Requirements() = default;
Requirements(const Requirements&) = default;
std::vector<Subsystem*>::const_iterator begin() const {
return m_subsystems.begin();
}
std::vector<Subsystem*>::const_iterator end() const {
return m_subsystems.end();
}
private:
std::vector<Subsystem*> m_subsystems;
};
} // namespace frc2

View File

@@ -0,0 +1,38 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#pragma once
#include <functional>
#include "frc2/command/CommandHelper.h"
#include "frc2/command/FunctionalCommand.h"
#include "frc2/command/Requirements.h"
namespace frc2 {
/**
* A command that runs a Runnable continuously. Has no end condition as-is;
* either subclass it or use Command.WithTimeout() or
* Command.Until() to give it one. If you only wish
* to execute a Runnable once, use InstantCommand.
*
* This class is provided by the NewCommands VendorDep
*/
class RunCommand : public CommandHelper<FunctionalCommand, RunCommand> {
public:
/**
* Creates a new RunCommand. The Runnable will be run continuously until the
* command ends. Does not run when disabled.
*
* @param toRun the Runnable to run
* @param requirements the subsystems to require
*/
explicit RunCommand(std::function<void()> toRun,
Requirements requirements = {});
RunCommand(RunCommand&& other) = default;
RunCommand(const RunCommand& other) = default;
};
} // namespace frc2

View File

@@ -0,0 +1,48 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#pragma once
#include <span>
#include <wpi/SmallSet.h>
#include "frc2/command/Command.h"
#include "frc2/command/CommandHelper.h"
namespace frc2 {
/**
* Schedules the given commands when this command is initialized. Useful for
* forking off from CommandGroups. Note that if run from a composition, the
* composition will not know about the status of the scheduled commands, and
* will treat this command as finishing instantly.
*
* This class is provided by the NewCommands VendorDep
*/
class ScheduleCommand : public CommandHelper<Command, ScheduleCommand> {
public:
/**
* Creates a new ScheduleCommand that schedules the given commands when
* initialized.
*
* @param toSchedule the commands to schedule
*/
explicit ScheduleCommand(std::span<Command* const> toSchedule);
explicit ScheduleCommand(Command* toSchedule);
ScheduleCommand(ScheduleCommand&& other) = default;
ScheduleCommand(const ScheduleCommand& other) = default;
void Initialize() override;
bool IsFinished() override;
bool RunsWhenDisabled() const override;
private:
wpi::SmallSet<Command*, 4> m_toSchedule;
};
} // namespace frc2

View File

@@ -0,0 +1,163 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#pragma once
#ifdef _WIN32
#pragma warning(push)
#pragma warning(disable : 4521)
#endif
#include <concepts>
#include <functional>
#include <memory>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>
#include <wpi/sendable/SendableBuilder.h>
#include "frc2/command/Command.h"
#include "frc2/command/PrintCommand.h"
namespace frc2 {
/**
* A command composition that runs one of a selection of commands using a
* selector and a key to command mapping.
*
* <p>The rules for command compositions apply: command instances that are
* passed to it are owned by the composition and cannot be added to any other
* composition or scheduled individually, and the composition requires all
* subsystems its components require.
*
* This class is provided by the NewCommands VendorDep
*/
template <typename Key>
class SelectCommand : public CommandHelper<Command, SelectCommand<Key>> {
public:
/**
* Creates a new SelectCommand.
*
* @param commands the map of commands to choose from
* @param selector the selector to determine which command to run
*/
template <std::derived_from<Command>... Commands>
explicit SelectCommand(std::function<Key()> selector,
std::pair<Key, Commands>... commands)
: m_selector{std::move(selector)} {
std::vector<std::pair<Key, std::unique_ptr<Command>>> foo;
((void)foo.emplace_back(
commands.first,
std::make_unique<std::decay_t<Commands>>(std::move(commands.second))),
...);
m_defaultCommand.SetComposed(true);
for (auto&& command : foo) {
CommandScheduler::GetInstance().RequireUngroupedAndUnscheduled(
command.second.get());
command.second.get()->SetComposed(true);
}
for (auto&& command : foo) {
this->AddRequirements(command.second->GetRequirements());
m_runsWhenDisabled &= command.second->RunsWhenDisabled();
if (command.second->GetInterruptionBehavior() ==
Command::InterruptionBehavior::kCancelSelf) {
m_interruptBehavior = Command::InterruptionBehavior::kCancelSelf;
}
m_commands.emplace(std::move(command.first), std::move(command.second));
}
}
SelectCommand(
std::function<Key()> selector,
std::vector<std::pair<Key, std::unique_ptr<Command>>>&& commands)
: m_selector{std::move(selector)} {
m_defaultCommand.SetComposed(true);
for (auto&& command : commands) {
CommandScheduler::GetInstance().RequireUngroupedAndUnscheduled(
command.second.get());
command.second.get()->SetComposed(true);
}
for (auto&& command : commands) {
this->AddRequirements(command.second->GetRequirements());
m_runsWhenDisabled &= command.second->RunsWhenDisabled();
if (command.second->GetInterruptionBehavior() ==
Command::InterruptionBehavior::kCancelSelf) {
m_interruptBehavior = Command::InterruptionBehavior::kCancelSelf;
}
m_commands.emplace(std::move(command.first), std::move(command.second));
}
}
// No copy constructors for command groups
SelectCommand(const SelectCommand& other) = delete;
// Prevent template expansion from emulating copy ctor
SelectCommand(SelectCommand&) = delete;
SelectCommand(SelectCommand&& other) = default;
void Initialize() override;
void Execute() override { m_selectedCommand->Execute(); }
void End(bool interrupted) override {
return m_selectedCommand->End(interrupted);
}
bool IsFinished() override { return m_selectedCommand->IsFinished(); }
bool RunsWhenDisabled() const override { return m_runsWhenDisabled; }
Command::InterruptionBehavior GetInterruptionBehavior() const override {
return m_interruptBehavior;
}
void InitSendable(wpi::SendableBuilder& builder) override {
Command::InitSendable(builder);
builder.AddStringProperty(
"selected",
[this] {
if (m_selectedCommand) {
return m_selectedCommand->GetName();
} else {
return std::string{"null"};
}
},
nullptr);
}
private:
std::unordered_map<Key, std::unique_ptr<Command>> m_commands;
std::function<Key()> m_selector;
Command* m_selectedCommand;
bool m_runsWhenDisabled = true;
Command::InterruptionBehavior m_interruptBehavior{
Command::InterruptionBehavior::kCancelIncoming};
PrintCommand m_defaultCommand{
"SelectCommand selector value does not correspond to any command!"};
};
template <typename T>
void SelectCommand<T>::Initialize() {
auto find = m_commands.find(m_selector());
if (find == m_commands.end()) {
m_selectedCommand = &m_defaultCommand;
} else {
m_selectedCommand = find->second.get();
}
m_selectedCommand->Initialize();
}
} // namespace frc2
#ifdef _WIN32
#pragma warning(pop)
#endif

View File

@@ -0,0 +1,110 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#pragma once
#ifdef _WIN32
#pragma warning(push)
#pragma warning(disable : 4521)
#endif
#include <limits>
#include <memory>
#include <type_traits>
#include <utility>
#include <vector>
#include <wpi/DecayedDerivedFrom.h>
#include "frc2/command/CommandHelper.h"
namespace frc2 {
const size_t invalid_index = std::numeric_limits<size_t>::max();
/**
* A command composition that runs a list of commands in sequence.
*
* <p>The rules for command compositions apply: command instances that are
* passed to it are owned by the composition and cannot be added to any other
* composition or scheduled individually, and the composition requires all
* subsystems its components require.
*
* This class is provided by the NewCommands VendorDep
*/
class SequentialCommandGroup
: public CommandHelper<Command, SequentialCommandGroup> {
public:
/**
* Creates a new SequentialCommandGroup. The given commands will be run
* sequentially, with the composition finishing when the last command
* finishes.
*
* @param commands the commands to include in this composition.
*/
explicit SequentialCommandGroup(
std::vector<std::unique_ptr<Command>>&& commands);
/**
* Creates a new SequentialCommandGroup. The given commands will be run
* sequentially, with the composition finishing when the last command
* finishes.
*
* @param commands the commands to include in this composition.
*/
template <wpi::DecayedDerivedFrom<Command>... Commands>
explicit SequentialCommandGroup(Commands&&... commands) {
AddCommands(std::forward<Commands>(commands)...);
}
SequentialCommandGroup(SequentialCommandGroup&& other) = default;
// No copy constructors for command groups
SequentialCommandGroup(const SequentialCommandGroup&) = delete;
// Prevent template expansion from emulating copy ctor
SequentialCommandGroup(SequentialCommandGroup&) = delete;
/**
* Adds the given commands to the group.
*
* @param commands Commands to add, in order of execution.
*/
template <wpi::DecayedDerivedFrom<Command>... Commands>
void AddCommands(Commands&&... commands) {
std::vector<std::unique_ptr<Command>> foo;
((void)foo.emplace_back(std::make_unique<std::decay_t<Commands>>(
std::forward<Commands>(commands))),
...);
AddCommands(std::move(foo));
}
void Initialize() final;
void Execute() final;
void End(bool interrupted) final;
bool IsFinished() final;
bool RunsWhenDisabled() const override;
Command::InterruptionBehavior GetInterruptionBehavior() const override;
void InitSendable(wpi::SendableBuilder& builder) override;
private:
void AddCommands(std::vector<std::unique_ptr<Command>>&& commands);
wpi::SmallVector<std::unique_ptr<Command>, 4> m_commands;
size_t m_currentCommandIndex{invalid_index};
bool m_runWhenDisabled{true};
Command::InterruptionBehavior m_interruptBehavior{
Command::InterruptionBehavior::kCancelIncoming};
};
} // namespace frc2
#ifdef _WIN32
#pragma warning(pop)
#endif

View File

@@ -0,0 +1,41 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#pragma once
#include <functional>
#include "frc2/command/CommandHelper.h"
#include "frc2/command/FunctionalCommand.h"
#include "frc2/command/Requirements.h"
namespace frc2 {
/**
* A command that runs a given runnable when it is initialized, and another
* runnable when it ends. Useful for running and then stopping a motor, or
* extending and then retracting a solenoid. Has no end condition as-is; either
* subclass it or use Command.WithTimeout() or Command.Until() to give
* it one.
*
* This class is provided by the NewCommands VendorDep
*/
class StartEndCommand
: public CommandHelper<FunctionalCommand, StartEndCommand> {
public:
/**
* Creates a new StartEndCommand. Will run the given runnables when the
* command starts and when it ends.
*
* @param onInit the Runnable to run on command init
* @param onEnd the Runnable to run on command end
* @param requirements the subsystems required by this command
*/
StartEndCommand(std::function<void()> onInit, std::function<void()> onEnd,
Requirements requirements = {});
StartEndCommand(StartEndCommand&& other) = default;
StartEndCommand(const StartEndCommand& other) = default;
};
} // namespace frc2

View File

@@ -0,0 +1,185 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#pragma once
#include <concepts>
#include <functional>
#include <string>
#include <utility>
#include <wpi/FunctionExtras.h>
#include "frc2/command/CommandScheduler.h"
namespace frc2 {
class Command;
class CommandPtr;
/**
* A robot subsystem. Subsystems are the basic unit of robot organization in
* the Command-based framework; they encapsulate low-level hardware objects
* (motor controllers, sensors, etc) and provide methods through which they can
* be used by Commands. Subsystems are used by the CommandScheduler's resource
* management system to ensure multiple robot actions are not "fighting" over
* the same hardware; Commands that use a subsystem should include that
* subsystem in their GetRequirements() method, and resources used within a
* subsystem should generally remain encapsulated and not be shared by other
* parts of the robot.
*
* <p>Subsystems must be registered with the scheduler with the
* CommandScheduler.RegisterSubsystem() method in order for the
* Periodic() method to be called. It is recommended that this method be called
* from the constructor of users' Subsystem implementations. The
* SubsystemBase class offers a simple base for user implementations
* that handles this.
*
* This class is provided by the NewCommands VendorDep
*
* @see Command
* @see CommandScheduler
* @see SubsystemBase
*/
class Subsystem {
public:
virtual ~Subsystem();
/**
* This method is called periodically by the CommandScheduler. Useful for
* updating subsystem-specific state that you don't want to offload to a
* Command. Teams should try to be consistent within their own codebases
* about which responsibilities will be handled by Commands, and which will be
* handled here.
*/
virtual void Periodic();
/**
* This method is called periodically by the CommandScheduler. Useful for
* updating subsystem-specific state that needs to be maintained for
* simulations, such as for updating simulation classes and setting simulated
* sensor readings.
*/
virtual void SimulationPeriodic();
/**
* Gets the name of this Subsystem.
*
* @return Name
*/
virtual std::string GetName() const;
/**
* Sets the default Command of the subsystem. The default command will be
* automatically scheduled when no other commands are scheduled that require
* the subsystem. Default commands should generally not end on their own, i.e.
* their IsFinished() method should always return false. Will automatically
* register this subsystem with the CommandScheduler.
*
* @param defaultCommand the default command to associate with this subsystem
*/
template <std::derived_from<Command> T>
void SetDefaultCommand(T&& defaultCommand) {
CommandScheduler::GetInstance().SetDefaultCommand(
this, std::forward<T>(defaultCommand));
}
/**
* Sets the default Command of the subsystem. The default command will be
* automatically scheduled when no other commands are scheduled that require
* the subsystem. Default commands should generally not end on their own, i.e.
* their IsFinished() method should always return false. Will automatically
* register this subsystem with the CommandScheduler.
*
* @param defaultCommand the default command to associate with this subsystem
*/
void SetDefaultCommand(CommandPtr&& defaultCommand);
/**
* Removes the default command for the subsystem. This will not cancel the
* default command if it is currently running.
*/
void RemoveDefaultCommand();
/**
* Gets the default command for this subsystem. Returns null if no default
* command is currently associated with the subsystem.
*
* @return the default command associated with this subsystem
*/
Command* GetDefaultCommand() const;
/**
* Returns the command currently running on this subsystem. Returns null if
* no command is currently scheduled that requires this subsystem.
*
* @return the scheduled command currently requiring this subsystem
*/
Command* GetCurrentCommand() const;
/**
* Registers this subsystem with the CommandScheduler, allowing its
* Periodic() method to be called when the scheduler runs.
*/
void Register();
/**
* Constructs a command that does nothing until interrupted. Requires this
* subsystem.
*
* @return the command
*/
[[nodiscard]]
CommandPtr Idle();
/**
* Constructs a command that runs an action once and finishes. Requires this
* subsystem.
*
* @param action the action to run
*/
CommandPtr RunOnce(std::function<void()> action);
/**
* Constructs a command that runs an action every iteration until interrupted.
* Requires this subsystem.
*
* @param action the action to run
*/
CommandPtr Run(std::function<void()> action);
/**
* Constructs a command that runs an action once and another action when the
* command is interrupted. Requires this subsystem.
*
* @param start the action to run on start
* @param end the action to run on interrupt
*/
CommandPtr StartEnd(std::function<void()> start, std::function<void()> end);
/**
* Constructs a command that runs an action every iteration until interrupted,
* and then runs a second action. Requires this subsystem.
*
* @param run the action to run every iteration
* @param end the action to run on interrupt
*/
CommandPtr RunEnd(std::function<void()> run, std::function<void()> end);
/**
* Constructs a command that runs an action once, and then runs an action
* every iteration until interrupted. Requires this subsystem.
*
* @param start the action to run on start
* @param run the action to run every iteration
*/
CommandPtr StartRun(std::function<void()> start, std::function<void()> run);
/**
* Constructs a DeferredCommand with the provided supplier. This subsystem is
* added as a requirement.
*
* @param supplier the command supplier.
* @return the command.
*/
CommandPtr Defer(wpi::unique_function<CommandPtr()> supplier);
};
} // namespace frc2

View File

@@ -0,0 +1,77 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#pragma once
#include <string>
#include <string_view>
#include <wpi/sendable/Sendable.h>
#include <wpi/sendable/SendableHelper.h>
#include "frc2/command/Subsystem.h"
namespace frc2 {
/**
* A base for subsystems that handles registration in the constructor, and
* provides a more intuitive method for setting the default command.
*
* This class is provided by the NewCommands VendorDep
*/
class SubsystemBase : public Subsystem,
public wpi::Sendable,
public wpi::SendableHelper<SubsystemBase> {
public:
void InitSendable(wpi::SendableBuilder& builder) override;
/**
* Gets the name of this Subsystem.
*
* @return Name
*/
std::string GetName() const override;
/**
* Sets the name of this Subsystem.
*
* @param name name
*/
void SetName(std::string_view name);
/**
* Gets the subsystem name of this Subsystem.
*
* @return Subsystem name
*/
std::string GetSubsystem() const;
/**
* Sets the subsystem name of this Subsystem.
*
* @param name subsystem name
*/
void SetSubsystem(std::string_view name);
/**
* Associate a Sendable with this Subsystem.
* Also update the child's name.
*
* @param name name to give child
* @param child sendable
*/
void AddChild(std::string name, wpi::Sendable* child);
protected:
/**
* Constructor. Telemetry/log name defaults to the classname.
*/
SubsystemBase();
/**
* Constructor.
*
* @param name Name of the subsystem for telemetry and logging.
*/
explicit SubsystemBase(std::string_view name);
};
} // namespace frc2

View File

@@ -0,0 +1,50 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#pragma once
#include <frc/Timer.h>
#include <units/time.h>
#include "frc2/command/Command.h"
#include "frc2/command/CommandHelper.h"
namespace frc2 {
/**
* A command that does nothing but takes a specified amount of time to finish.
*
* This class is provided by the NewCommands VendorDep
*/
class WaitCommand : public CommandHelper<Command, WaitCommand> {
public:
/**
* Creates a new WaitCommand. This command will do nothing, and end after the
* specified duration.
*
* @param duration the time to wait
*/
explicit WaitCommand(units::second_t duration);
WaitCommand(WaitCommand&& other) = default;
WaitCommand(const WaitCommand& other) = default;
void Initialize() override;
void End(bool interrupted) override;
bool IsFinished() override;
bool RunsWhenDisabled() const override;
void InitSendable(wpi::SendableBuilder& builder) override;
protected:
/// The timer used for waiting.
frc::Timer m_timer;
private:
units::second_t m_duration;
};
} // namespace frc2

View File

@@ -0,0 +1,54 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#pragma once
#include <functional>
#include <units/time.h>
#include "frc2/command/Command.h"
#include "frc2/command/CommandHelper.h"
namespace frc2 {
/**
* A command that does nothing but ends after a specified match time or
* condition. Useful for CommandGroups.
*
* This class is provided by the NewCommands VendorDep
*/
class WaitUntilCommand : public CommandHelper<Command, WaitUntilCommand> {
public:
/**
* Creates a new WaitUntilCommand that ends after a given condition becomes
* true.
*
* @param condition the condition to determine when to end
*/
explicit WaitUntilCommand(std::function<bool()> condition);
/**
* Creates a new WaitUntilCommand that ends after a given match time.
*
* <p>NOTE: The match timer used for this command is UNOFFICIAL. Using this
* command does NOT guarantee that the time at which the action is performed
* will be judged to be legal by the referees. When in doubt, add a safety
* factor or time the action manually.
*
* @param time the match time after which to end, in seconds
*/
explicit WaitUntilCommand(units::second_t time);
WaitUntilCommand(WaitUntilCommand&& other) = default;
WaitUntilCommand(const WaitUntilCommand& other) = default;
bool IsFinished() override;
bool RunsWhenDisabled() const override;
private:
std::function<bool()> m_condition;
};
} // namespace frc2

View File

@@ -0,0 +1,79 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#pragma once
#ifdef _WIN32
#pragma warning(push)
#pragma warning(disable : 4521)
#endif
#include <concepts>
#include <memory>
#include <utility>
#include "frc2/command/Command.h"
#include "frc2/command/CommandHelper.h"
namespace frc2 {
/**
* A class used internally to wrap commands while overriding a specific method;
* all other methods will call through to the wrapped command.
*
* <p>Wrapped commands may only be used through the wrapper, trying to directly
* schedule them or add them to a group will throw an exception.
*/
class WrapperCommand : public CommandHelper<Command, WrapperCommand> {
public:
/**
* Wrap a command.
*
* @param command the command being wrapped. Trying to directly schedule this
* command or add it to a group will throw an exception.
*/
explicit WrapperCommand(std::unique_ptr<Command>&& command);
/**
* Wrap a command.
*
* @param command the command being wrapped. Trying to directly schedule this
* command or add it to a group will throw an exception.
*/
template <std::derived_from<Command> T>
// NOLINTNEXTLINE(bugprone-forwarding-reference-overload)
explicit WrapperCommand(T&& command)
: WrapperCommand(
std::make_unique<std::decay_t<T>>(std::forward<T>(command))) {}
WrapperCommand(WrapperCommand&& other) = default;
// No copy constructors for command groups
WrapperCommand(const WrapperCommand& other) = delete;
// Prevent template expansion from emulating copy ctor
WrapperCommand(WrapperCommand&) = delete;
void Initialize() override;
void Execute() override;
bool IsFinished() override;
void End(bool interrupted) override;
bool RunsWhenDisabled() const override;
InterruptionBehavior GetInterruptionBehavior() const override;
wpi::SmallSet<Subsystem*, 4> GetRequirements() const override;
protected:
/// Command being wrapped.
std::unique_ptr<Command> m_command;
};
} // namespace frc2
#ifdef _WIN32
#pragma warning(pop)
#endif

View File

@@ -0,0 +1,434 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#pragma once
#include <frc/Gamepad.h>
#include "frc2/command/CommandScheduler.h"
#include "frc2/command/button/CommandGenericHID.h"
#include "frc2/command/button/Trigger.h"
namespace frc2 {
/**
* A version of {@link frc::Gamepad} with {@link Trigger} factories for
* command-based.
*
* @see frc::Gamepad
*/
class CommandGamepad : public CommandGenericHID {
public:
/**
* Construct an instance of a controller.
*
* @param port The port index on the Driver Station that the controller is
* plugged into.
*/
explicit CommandGamepad(int port);
/**
* Get the underlying GenericHID object.
*
* @return the wrapped GenericHID object
*/
frc::Gamepad& GetHID();
/**
* Constructs a Trigger instance around the South Face button's
* digital signal.
*
* @param loop the event loop instance to attach the event to. Defaults to the
* CommandScheduler's default loop.
* @return a Trigger instance representing the South Face button's
* digital signal attached to the given loop.
*/
Trigger SouthFace(frc::EventLoop* loop = CommandScheduler::GetInstance()
.GetDefaultButtonLoop()) const;
/**
* Constructs a Trigger instance around the East Face button's
* digital signal.
*
* @param loop the event loop instance to attach the event to. Defaults to the
* CommandScheduler's default loop.
* @return a Trigger instance representing the East Face button's
* digital signal attached to the given loop.
*/
Trigger EastFace(frc::EventLoop* loop = CommandScheduler::GetInstance()
.GetDefaultButtonLoop()) const;
/**
* Constructs a Trigger instance around the West Face button's
* digital signal.
*
* @param loop the event loop instance to attach the event to. Defaults to the
* CommandScheduler's default loop.
* @return a Trigger instance representing the West Face button's
* digital signal attached to the given loop.
*/
Trigger WestFace(frc::EventLoop* loop = CommandScheduler::GetInstance()
.GetDefaultButtonLoop()) const;
/**
* Constructs a Trigger instance around the North Face button's
* digital signal.
*
* @param loop the event loop instance to attach the event to. Defaults to the
* CommandScheduler's default loop.
* @return a Trigger instance representing the North Face button's
* digital signal attached to the given loop.
*/
Trigger NorthFace(frc::EventLoop* loop = CommandScheduler::GetInstance()
.GetDefaultButtonLoop()) const;
/**
* Constructs a Trigger instance around the Back button's
* digital signal.
*
* @param loop the event loop instance to attach the event to. Defaults to the
* CommandScheduler's default loop.
* @return a Trigger instance representing the Back button's
* digital signal attached to the given loop.
*/
Trigger Back(frc::EventLoop* loop = CommandScheduler::GetInstance()
.GetDefaultButtonLoop()) const;
/**
* Constructs a Trigger instance around the Guide button's
* digital signal.
*
* @param loop the event loop instance to attach the event to. Defaults to the
* CommandScheduler's default loop.
* @return a Trigger instance representing the Guide button's
* digital signal attached to the given loop.
*/
Trigger Guide(frc::EventLoop* loop = CommandScheduler::GetInstance()
.GetDefaultButtonLoop()) const;
/**
* Constructs a Trigger instance around the Start button's
* digital signal.
*
* @param loop the event loop instance to attach the event to. Defaults to the
* CommandScheduler's default loop.
* @return a Trigger instance representing the Start button's
* digital signal attached to the given loop.
*/
Trigger Start(frc::EventLoop* loop = CommandScheduler::GetInstance()
.GetDefaultButtonLoop()) const;
/**
* Constructs a Trigger instance around the left stick button's
* digital signal.
*
* @param loop the event loop instance to attach the event to. Defaults to the
* CommandScheduler's default loop.
* @return a Trigger instance representing the left stick button's
* digital signal attached to the given loop.
*/
Trigger LeftStick(frc::EventLoop* loop = CommandScheduler::GetInstance()
.GetDefaultButtonLoop()) const;
/**
* Constructs a Trigger instance around the right stick button's
* digital signal.
*
* @param loop the event loop instance to attach the event to. Defaults to the
* CommandScheduler's default loop.
* @return a Trigger instance representing the right stick button's
* digital signal attached to the given loop.
*/
Trigger RightStick(frc::EventLoop* loop = CommandScheduler::GetInstance()
.GetDefaultButtonLoop()) const;
/**
* Constructs a Trigger instance around the right shoulder button's
* digital signal.
*
* @param loop the event loop instance to attach the event to. Defaults to the
* CommandScheduler's default loop.
* @return a Trigger instance representing the right shoulder button's
* digital signal attached to the given loop.
*/
Trigger LeftShoulder(
frc::EventLoop* loop =
CommandScheduler::GetInstance().GetDefaultButtonLoop()) const;
/**
* Constructs a Trigger instance around the right shoulder button's
* digital signal.
*
* @param loop the event loop instance to attach the event to. Defaults to the
* CommandScheduler's default loop.
* @return a Trigger instance representing the right shoulder button's
* digital signal attached to the given loop.
*/
Trigger RightShoulder(
frc::EventLoop* loop =
CommandScheduler::GetInstance().GetDefaultButtonLoop()) const;
/**
* Constructs a Trigger instance around the D-pad up button's
* digital signal.
*
* @param loop the event loop instance to attach the event to. Defaults to the
* CommandScheduler's default loop.
* @return a Trigger instance representing the D-pad up button's
* digital signal attached to the given loop.
*/
Trigger DpadUp(frc::EventLoop* loop = CommandScheduler::GetInstance()
.GetDefaultButtonLoop()) const;
/**
* Constructs a Trigger instance around the D-pad down button's
* digital signal.
*
* @param loop the event loop instance to attach the event to. Defaults to the
* CommandScheduler's default loop.
* @return a Trigger instance representing the D-pad down button's
* digital signal attached to the given loop.
*/
Trigger DpadDown(frc::EventLoop* loop = CommandScheduler::GetInstance()
.GetDefaultButtonLoop()) const;
/**
* Constructs a Trigger instance around the D-pad left button's
* digital signal.
*
* @param loop the event loop instance to attach the event to. Defaults to the
* CommandScheduler's default loop.
* @return a Trigger instance representing the D-pad left button's
* digital signal attached to the given loop.
*/
Trigger DpadLeft(frc::EventLoop* loop = CommandScheduler::GetInstance()
.GetDefaultButtonLoop()) const;
/**
* Constructs a Trigger instance around the D-pad right button's
* digital signal.
*
* @param loop the event loop instance to attach the event to. Defaults to the
* CommandScheduler's default loop.
* @return a Trigger instance representing the D-pad right button's
* digital signal attached to the given loop.
*/
Trigger DpadRight(frc::EventLoop* loop = CommandScheduler::GetInstance()
.GetDefaultButtonLoop()) const;
/**
* Constructs a Trigger instance around the Miscellaneous 1 button's
* digital signal.
*
* @param loop the event loop instance to attach the event to. Defaults to the
* CommandScheduler's default loop.
* @return a Trigger instance representing the Miscellaneous 1 button's
* digital signal attached to the given loop.
*/
Trigger Misc1(frc::EventLoop* loop = CommandScheduler::GetInstance()
.GetDefaultButtonLoop()) const;
/**
* Constructs a Trigger instance around the Right Paddle 1 button's
* digital signal.
*
* @param loop the event loop instance to attach the event to. Defaults to the
* CommandScheduler's default loop.
* @return a Trigger instance representing the Right Paddle 1 button's
* digital signal attached to the given loop.
*/
Trigger RightPaddle1(
frc::EventLoop* loop =
CommandScheduler::GetInstance().GetDefaultButtonLoop()) const;
/**
* Constructs a Trigger instance around the Left Paddle 1 button's
* digital signal.
*
* @param loop the event loop instance to attach the event to. Defaults to the
* CommandScheduler's default loop.
* @return a Trigger instance representing the Left Paddle 1 button's
* digital signal attached to the given loop.
*/
Trigger LeftPaddle1(frc::EventLoop* loop = CommandScheduler::GetInstance()
.GetDefaultButtonLoop()) const;
/**
* Constructs a Trigger instance around the Right Paddle 2 button's
* digital signal.
*
* @param loop the event loop instance to attach the event to. Defaults to the
* CommandScheduler's default loop.
* @return a Trigger instance representing the Right Paddle 2 button's
* digital signal attached to the given loop.
*/
Trigger RightPaddle2(
frc::EventLoop* loop =
CommandScheduler::GetInstance().GetDefaultButtonLoop()) const;
/**
* Constructs a Trigger instance around the Left Paddle 2 button's
* digital signal.
*
* @param loop the event loop instance to attach the event to. Defaults to the
* CommandScheduler's default loop.
* @return a Trigger instance representing the Left Paddle 2 button's
* digital signal attached to the given loop.
*/
Trigger LeftPaddle2(frc::EventLoop* loop = CommandScheduler::GetInstance()
.GetDefaultButtonLoop()) const;
/**
* Constructs a Trigger instance around the Touchpad button's
* digital signal.
*
* @param loop the event loop instance to attach the event to. Defaults to the
* CommandScheduler's default loop.
* @return a Trigger instance representing the Touchpad button's
* digital signal attached to the given loop.
*/
Trigger Touchpad(frc::EventLoop* loop = CommandScheduler::GetInstance()
.GetDefaultButtonLoop()) const;
/**
* Constructs a Trigger instance around the Miscellaneous 2 button's
* digital signal.
*
* @param loop the event loop instance to attach the event to. Defaults to the
* CommandScheduler's default loop.
* @return a Trigger instance representing the Miscellaneous 2 button's
* digital signal attached to the given loop.
*/
Trigger Misc2(frc::EventLoop* loop = CommandScheduler::GetInstance()
.GetDefaultButtonLoop()) const;
/**
* Constructs a Trigger instance around the Miscellaneous 3 button's
* digital signal.
*
* @param loop the event loop instance to attach the event to. Defaults to the
* CommandScheduler's default loop.
* @return a Trigger instance representing the Miscellaneous 3 button's
* digital signal attached to the given loop.
*/
Trigger Misc3(frc::EventLoop* loop = CommandScheduler::GetInstance()
.GetDefaultButtonLoop()) const;
/**
* Constructs a Trigger instance around the Miscellaneous 4 button's
* digital signal.
*
* @param loop the event loop instance to attach the event to. Defaults to the
* CommandScheduler's default loop.
* @return a Trigger instance representing the Miscellaneous 4 button's
* digital signal attached to the given loop.
*/
Trigger Misc4(frc::EventLoop* loop = CommandScheduler::GetInstance()
.GetDefaultButtonLoop()) const;
/**
* Constructs a Trigger instance around the Miscellaneous 5 button's
* digital signal.
*
* @param loop the event loop instance to attach the event to. Defaults to the
* CommandScheduler's default loop.
* @return a Trigger instance representing the Miscellaneous 5 button's
* digital signal attached to the given loop.
*/
Trigger Misc5(frc::EventLoop* loop = CommandScheduler::GetInstance()
.GetDefaultButtonLoop()) const;
/**
* Constructs a Trigger instance around the Miscellaneous 6 button's
* digital signal.
*
* @param loop the event loop instance to attach the event to. Defaults to the
* CommandScheduler's default loop.
* @return a Trigger instance representing the Miscellaneous 6 button's
* digital signal attached to the given loop.
*/
Trigger Misc6(frc::EventLoop* loop = CommandScheduler::GetInstance()
.GetDefaultButtonLoop()) const;
/**
* Constructs a Trigger instance around the axis value of the left trigger.
* The returned Trigger will be true when the axis value is greater than
* {@code threshold}.
*
* @param threshold the minimum axis value for the returned Trigger to be
* true. This value should be in the range [0, 1] where 0 is the unpressed
* state of the axis. Defaults to 0.5.
* @param loop the event loop instance to attach the Trigger to. Defaults to
* the CommandScheduler's default loop.
* @return a Trigger instance that is true when the left trigger's axis
* exceeds the provided threshold, attached to the given loop
*/
Trigger LeftTrigger(double threshold = 0.5,
frc::EventLoop* loop = CommandScheduler::GetInstance()
.GetDefaultButtonLoop()) const;
/**
* Constructs a Trigger instance around the axis value of the right trigger.
* The returned Trigger will be true when the axis value is greater than
* {@code threshold}.
*
* @param threshold the minimum axis value for the returned Trigger to be
* true. This value should be in the range [0, 1] where 0 is the unpressed
* state of the axis. Defaults to 0.5.
* @param loop the event loop instance to attach the Trigger to. Defaults to
* the CommandScheduler's default loop.
* @return a Trigger instance that is true when the right trigger's axis
* exceeds the provided threshold, attached to the given loop
*/
Trigger RightTrigger(
double threshold = 0.5,
frc::EventLoop* loop =
CommandScheduler::GetInstance().GetDefaultButtonLoop()) const;
/**
* Get the X axis value of left side of the controller. Right is positive.
*
* @return The axis value.
*/
double GetLeftX() const;
/**
* Get the Y axis value of left side of the controller. Back is positive.
*
* @return The axis value.
*/
double GetLeftY() const;
/**
* Get the X axis value of right side of the controller. Right is positive.
*
* @return The axis value.
*/
double GetRightX() const;
/**
* Get the Y axis value of right side of the controller. Back is positive.
*
* @return The axis value.
*/
double GetRightY() const;
/**
* Get the left trigger axis value of the controller. Note that this axis is
* bound to the range of [0, 1] as opposed to the usual [-1, 1].
*
* @return The axis value.
*/
double GetLeftTriggerAxis() const;
/**
* Get the right trigger axis value of the controller. Note that this axis is
* bound to the range of [0, 1] as opposed to the usual [-1, 1].
*
* @return The axis value.
*/
double GetRightTriggerAxis() const;
private:
frc::Gamepad m_hid;
};
} // namespace frc2

View File

@@ -0,0 +1,264 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#pragma once
#include <frc/DriverStation.h>
#include <frc/GenericHID.h>
#include "Trigger.h"
#include "frc2/command/CommandScheduler.h"
namespace frc2 {
/**
* A version of {@link frc::GenericHID} with {@link Trigger} factories for
* command-based.
*
* @see GenericHID
*/
class CommandGenericHID {
public:
/**
* Construct an instance of a device.
*
* @param port The port index on the Driver Station that the device is plugged
* into.
*/
explicit CommandGenericHID(int port);
/**
* Get the underlying GenericHID object.
*
* @return the wrapped GenericHID object
*/
frc::GenericHID& GetHID();
/**
* Constructs an event instance around this button's digital signal.
*
* @param button the button index
* @param loop the event loop instance to attach the event to. Defaults to the
* CommandScheduler's default loop.
* @return an event instance representing the button's digital signal attached
* to the given loop.
*/
Trigger Button(int button,
frc::EventLoop* loop = CommandScheduler::GetInstance()
.GetDefaultButtonLoop()) const;
/**
* Constructs a Trigger instance based around this angle of a POV on the HID.
*
* @param loop the event loop instance to attach the event to. Defaults to
* {@link CommandScheduler::GetDefaultButtonLoop() the default command
* scheduler button loop}.
* @param angle POV angle.
* @return a Trigger instance based around this angle of a POV on the HID.
*/
Trigger POV(frc::DriverStation::POVDirection angle,
frc::EventLoop* loop =
CommandScheduler::GetInstance().GetDefaultButtonLoop()) const;
/**
* Constructs a Trigger instance based around this angle of a POV on the HID.
*
* @param loop the event loop instance to attach the event to. Defaults to
* {@link CommandScheduler::GetDefaultButtonLoop() the default command
* scheduler button loop}.
* @param pov index of the POV to read (starting at 0). Defaults to 0.
* @param angle POV angle.
* @return a Trigger instance based around this angle of a POV on the HID.
*/
Trigger POV(int pov, frc::DriverStation::POVDirection angle,
frc::EventLoop* loop =
CommandScheduler::GetInstance().GetDefaultButtonLoop()) const;
/**
* Constructs a Trigger instance based around the up direction of the
* default (index 0) POV on the HID.
*
* @param loop the event loop instance to attach the event to. Defaults to
* {@link CommandScheduler::GetDefaultButtonLoop() the default command
* scheduler button loop}.
* @return a Trigger instance based around the up direction of a POV on the
* HID.
*/
Trigger POVUp(frc::EventLoop* loop = CommandScheduler::GetInstance()
.GetDefaultButtonLoop()) const;
/**
* Constructs a Trigger instance based around the up right direction
* of the default (index 0) POV on the HID.
*
* @param loop the event loop instance to attach the event to. Defaults to
* {@link CommandScheduler::GetDefaultButtonLoop() the default command
* scheduler button loop}.
* @return a Trigger instance based around the up right direction of a POV on
* the HID.
*/
Trigger POVUpRight(frc::EventLoop* loop = CommandScheduler::GetInstance()
.GetDefaultButtonLoop()) const;
/**
* Constructs a Trigger instance based around the right direction of
* the default (index 0) POV on the HID.
*
* @param loop the event loop instance to attach the event to. Defaults to
* {@link CommandScheduler::GetDefaultButtonLoop() the default command
* scheduler button loop}.
* @return a Trigger instance based around the right direction of a POV on the
* HID.
*/
Trigger POVRight(frc::EventLoop* loop = CommandScheduler::GetInstance()
.GetDefaultButtonLoop()) const;
/**
* Constructs a Trigger instance based around the down right direction
* of the default (index 0) POV on the HID.
*
* @return a Trigger instance based around the down right direction of a POV
* on the HID.
*/
Trigger POVDownRight(
frc::EventLoop* loop =
CommandScheduler::GetInstance().GetDefaultButtonLoop()) const;
/**
* Constructs a Trigger instance based around the down direction of
* the default (index 0) POV on the HID.
*
* @param loop the event loop instance to attach the event to. Defaults to
* {@link CommandScheduler::GetDefaultButtonLoop() the default command
* scheduler button loop}.
* @return a Trigger instance based around the down direction of a POV on
* the HID.
*/
Trigger POVDown(frc::EventLoop* loop = CommandScheduler::GetInstance()
.GetDefaultButtonLoop()) const;
/**
* Constructs a Trigger instance based around the down left direction
* of the default (index 0) POV on the HID.
*
* @param loop the event loop instance to attach the event to. Defaults to
* {@link CommandScheduler::GetDefaultButtonLoop() the default command
* scheduler button loop}.
* @return a Trigger instance based around the down left direction of a POV on
* the HID.
*/
Trigger POVDownLeft(frc::EventLoop* loop = CommandScheduler::GetInstance()
.GetDefaultButtonLoop()) const;
/**
* Constructs a Trigger instance based around the left direction of
* the default (index 0) POV on the HID.
*
* @param loop the event loop instance to attach the event to. Defaults to
* {@link CommandScheduler::GetDefaultButtonLoop() the default command
* scheduler button loop}.
* @return a Trigger instance based around the left direction of a POV on
* the HID.
*/
Trigger POVLeft(frc::EventLoop* loop = CommandScheduler::GetInstance()
.GetDefaultButtonLoop()) const;
/**
* Constructs a Trigger instance based around the up left direction
* of the default (index 0) POV on the HID.
*
* @param loop the event loop instance to attach the event to. Defaults to
* {@link CommandScheduler::GetDefaultButtonLoop() the default command
* scheduler button loop}.
* @return a Trigger instance based around the up left direction of a POV on
* the HID.
*/
Trigger POVUpLeft(frc::EventLoop* loop = CommandScheduler::GetInstance()
.GetDefaultButtonLoop()) const;
/**
* Constructs a Trigger instance based around the center (not pressed)
* position of the default (index 0) POV on the HID.
*
* @param loop the event loop instance to attach the event to. Defaults to
* {@link CommandScheduler::GetDefaultButtonLoop() the default command
* scheduler button loop}.
* @return a Trigger instance based around the center position of a POV on the
* HID.
*/
Trigger POVCenter(frc::EventLoop* loop = CommandScheduler::GetInstance()
.GetDefaultButtonLoop()) const;
/**
* Constructs a Trigger instance that is true when the axis value is less than
* {@code threshold}, attached to {@link
* CommandScheduler::GetDefaultButtonLoop() the default command scheduler
* button loop}.
* @param axis The axis to read, starting at 0.
* @param threshold The value below which this trigger should return true.
* @param loop the event loop instance to attach the event to. Defaults to
* {@link CommandScheduler::GetDefaultButtonLoop() the default command
* scheduler button loop}.
* @return a Trigger instance that is true when the axis value is less than
* the provided threshold.
*/
Trigger AxisLessThan(
int axis, double threshold,
frc::EventLoop* loop =
CommandScheduler::GetInstance().GetDefaultButtonLoop()) const;
/**
* Constructs a Trigger instance that is true when the axis value is greater
* than {@code threshold}, attached to {@link
* CommandScheduler::GetDefaultButtonLoop() the default command scheduler
* button loop}.
* @param axis The axis to read, starting at 0.
* @param threshold The value below which this trigger should return true.
* @param loop the event loop instance to attach the event to. Defaults to
* {@link CommandScheduler::GetDefaultButtonLoop() the default command
* scheduler button loop}.
* @return a Trigger instance that is true when the axis value is greater than
* the provided threshold.
*/
Trigger AxisGreaterThan(
int axis, double threshold,
frc::EventLoop* loop =
CommandScheduler::GetInstance().GetDefaultButtonLoop()) const;
/**
* Constructs a Trigger instance that is true when the axis magnitude value is
* greater than {@code threshold}, attached to the given loop.
*
* @param axis The axis to read, starting at 0
* @param threshold The value above which this trigger should return true.
* @param loop the event loop instance to attach the trigger to.
* @return a Trigger instance that is true when the axis magnitude value is
* greater than the provided threshold.
*/
Trigger AxisMagnitudeGreaterThan(
int axis, double threshold,
frc::EventLoop* loop =
CommandScheduler::GetInstance().GetDefaultButtonLoop()) const;
/**
* Set the rumble output for the HID.
*
* The DS currently supports 2 rumble values, left rumble and right rumble.
*
* @param type Which rumble value to set
* @param value The normalized value (0 to 1) to set the rumble to
*/
void SetRumble(frc::GenericHID::RumbleType type, double value);
/**
* Get if the HID is connected.
*
* @return true if the HID is connected
*/
bool IsConnected() const;
private:
frc::GenericHID m_hid;
};
} // namespace frc2

View File

@@ -0,0 +1,78 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#pragma once
#include <frc/Joystick.h>
#include "Trigger.h"
#include "frc2/command/CommandScheduler.h"
#include "frc2/command/button/CommandGenericHID.h"
namespace frc2 {
/**
* A version of {@link frc::Joystick} with {@link Trigger} factories for
* command-based.
*
* @see frc::Joystick
*/
class CommandJoystick : public CommandGenericHID {
public:
/**
* Construct an instance of a controller.
*
* @param port The port index on the Driver Station that the controller is
* plugged into.
*/
explicit CommandJoystick(int port);
/**
* Get the underlying GenericHID object.
*
* @return the wrapped GenericHID object
*/
frc::Joystick& GetHID();
/**
* Constructs an event instance around the trigger button's digital signal.
*
* @param loop the event loop instance to attach the event to. Defaults to the
* CommandScheduler's default loop.
* @return an event instance representing the trigger button's digital signal
* attached to the given loop.
*/
class Trigger Trigger(
frc::EventLoop* loop =
CommandScheduler::GetInstance().GetDefaultButtonLoop()) const;
/**
* Constructs an event instance around the top button's digital signal.
*
* @param loop the event loop instance to attach the event to. Defaults to the
* CommandScheduler's default loop.
* @return an event instance representing the top button's digital signal
* attached to the given loop.
*/
class Trigger Top(frc::EventLoop* loop = CommandScheduler::GetInstance()
.GetDefaultButtonLoop()) const;
/**
* Get the magnitude of the vector formed by the joystick's
* current position relative to its origin.
*
* @return The magnitude of the direction vector
*/
double GetMagnitude() const;
/**
* Get the direction of the vector formed by the joystick and its origin. 0 is
* forward and clockwise is positive. (Straight right is π/2 radians or 90
* degrees.)
*
* @return The direction of the vector.
*/
units::radian_t GetDirection() const;
private:
frc::Joystick m_hid;
};
} // namespace frc2

View File

@@ -0,0 +1,32 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#pragma once
#include <frc/GenericHID.h>
#include "Trigger.h"
namespace frc2 {
/**
* A class used to bind command scheduling to joystick button presses. Can be
* composed with other buttons with the operators in Trigger.
*
* This class is provided by the NewCommands VendorDep
*
* @see Trigger
*/
class JoystickButton : public Trigger {
public:
/**
* Creates a JoystickButton that commands can be bound to.
*
* @param joystick The joystick on which the button is located.
* @param buttonNumber The number of the button on the joystick.
*/
explicit JoystickButton(frc::GenericHID* joystick, int buttonNumber)
: Trigger([joystick, buttonNumber] {
return joystick->GetRawButton(buttonNumber);
}) {}
};
} // namespace frc2

View File

@@ -0,0 +1,65 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#pragma once
#include <memory>
#include <string_view>
#include <networktables/BooleanTopic.h>
#include <networktables/NetworkTable.h>
#include <networktables/NetworkTableInstance.h>
#include "Trigger.h"
namespace frc2 {
/**
* A Button that uses a NetworkTable boolean field.
*
* This class is provided by the NewCommands VendorDep
*/
class NetworkButton : public Trigger {
public:
/**
* Creates a NetworkButton that commands can be bound to.
*
* @param topic The boolean topic that contains the value.
*/
explicit NetworkButton(nt::BooleanTopic topic);
/**
* Creates a NetworkButton that commands can be bound to.
*
* @param sub The boolean subscriber that provides the value.
*/
explicit NetworkButton(nt::BooleanSubscriber sub);
/**
* Creates a NetworkButton that commands can be bound to.
*
* @param table The table where the networktable value is located.
* @param field The field that is the value.
*/
NetworkButton(std::shared_ptr<nt::NetworkTable> table,
std::string_view field);
/**
* Creates a NetworkButton that commands can be bound to.
*
* @param table The table where the networktable value is located.
* @param field The field that is the value.
*/
NetworkButton(std::string_view table, std::string_view field);
/**
* Creates a NetworkButton that commands can be bound to.
*
* @param inst The NetworkTable instance to use
* @param table The table where the networktable value is located.
* @param field The field that is the value.
*/
NetworkButton(nt::NetworkTableInstance inst, std::string_view table,
std::string_view field);
};
} // namespace frc2

View File

@@ -0,0 +1,36 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#pragma once
#include <frc/DriverStation.h>
#include <frc/GenericHID.h>
#include "Trigger.h"
namespace frc2 {
/**
* A class used to bind command scheduling to joystick POV presses. Can be
* composed with other buttons with the operators in Trigger.
*
* This class is provided by the NewCommands VendorDep
*
* @see Trigger
*/
class POVButton : public Trigger {
public:
/**
* Creates a POVButton that commands can be bound to.
*
* @param joystick The joystick on which the button is located.
* @param angle The angle of the POV corresponding to a button press.
* @param povNumber The number of the POV on the joystick.
*/
POVButton(frc::GenericHID* joystick, frc::DriverStation::POVDirection angle,
int povNumber = 0)
: Trigger([joystick, angle, povNumber] {
return joystick->GetPOV(povNumber) == angle;
}) {}
};
} // namespace frc2

View File

@@ -0,0 +1,50 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#pragma once
#include "frc2/command/button/Trigger.h"
namespace frc2 {
/**
* A class containing static Trigger factories for running callbacks when robot
* mode changes.
*/
class RobotModeTriggers {
public:
RobotModeTriggers() = delete;
/**
* Returns a trigger that is true when the robot is enabled in autonomous
* mode.
*
* @return A trigger that is true when the robot is enabled in autonomous
* mode.
*/
static Trigger Autonomous();
/**
* Returns a trigger that is true when the robot is enabled in teleop mode.
*
* @return A trigger that is true when the robot is enabled in teleop mode.
*/
static Trigger Teleop();
/**
* Returns a trigger that is true when the robot is disabled.
*
* @return A trigger that is true when the robot is disabled.
*/
static Trigger Disabled();
/**
* Returns a trigger that is true when the robot is enabled in test mode.
*
* @return A trigger that is true when the robot is enabled in test mode.
*/
static Trigger Test();
};
} // namespace frc2

View File

@@ -0,0 +1,305 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#pragma once
#include <functional>
#include <utility>
#include <frc/event/BooleanEvent.h>
#include <frc/event/EventLoop.h>
#include <frc/filter/Debouncer.h>
#include <units/time.h>
#include <wpi/FunctionExtras.h>
#include "frc2/command/Command.h"
#include "frc2/command/CommandScheduler.h"
namespace frc2 {
class Command;
/**
* This class provides an easy way to link commands to conditions.
*
* <p>It is very easy to link a button to a command. For instance, you could
* link the trigger button of a joystick to a "score" command.
*
* <p>Triggers can easily be composed for advanced functionality using the
* {@link #operator!}, {@link #operator||}, {@link #operator&&} operators.
*
* <p>This class is provided by the NewCommands VendorDep
*/
class Trigger {
public:
/**
* Creates a new trigger based on the given condition.
*
* <p>Polled by the default scheduler button loop.
*
* @param condition the condition represented by this trigger
*/
explicit Trigger(std::function<bool()> condition)
: Trigger{CommandScheduler::GetInstance().GetDefaultButtonLoop(),
std::move(condition)} {}
/**
* Creates a new trigger based on the given condition.
*
* @param loop The loop instance that polls this trigger.
* @param condition the condition represented by this trigger
*/
Trigger(frc::EventLoop* loop, std::function<bool()> condition)
: m_loop{loop}, m_condition{std::move(condition)} {}
/**
* Create a new trigger that is always `false`.
*/
Trigger() : Trigger([] { return false; }) {}
Trigger(const Trigger& other);
/**
* Starts the command when the condition changes.
*
* @param command the command to start
* @return this trigger, so calls can be chained
*/
Trigger OnChange(Command* command);
/**
* Starts the command when the condition changes. Moves command ownership to
* the button scheduler.
*
* @param command the command to start
* @return this trigger, so calls can be chained
*/
Trigger OnChange(CommandPtr&& command);
/**
* Starts the given command whenever the condition changes from `false` to
* `true`.
*
* <p>Takes a raw pointer, and so is non-owning; users are responsible for the
* lifespan of the command.
*
* @param command the command to start
* @return this trigger, so calls can be chained
*/
Trigger OnTrue(Command* command);
/**
* Starts the given command whenever the condition changes from `false` to
* `true`. Moves command ownership to the button scheduler.
*
* @param command The command to bind.
* @return The trigger, for chained calls.
*/
Trigger OnTrue(CommandPtr&& command);
/**
* Starts the given command whenever the condition changes from `true` to
* `false`.
*
* <p>Takes a raw pointer, and so is non-owning; users are responsible for the
* lifespan of the command.
*
* @param command the command to start
* @return this trigger, so calls can be chained
*/
Trigger OnFalse(Command* command);
/**
* Starts the given command whenever the condition changes from `true` to
* `false`.
*
* @param command The command to bind.
* @return The trigger, for chained calls.
*/
Trigger OnFalse(CommandPtr&& command);
/**
* Starts the given command when the condition changes to `true` and cancels
* it when the condition changes to `false`.
*
* <p>Doesn't re-start the command if it ends while the condition is still
* `true`. If the command should restart, see RepeatCommand.
*
* <p>Takes a raw pointer, and so is non-owning; users are responsible for the
* lifespan of the command.
*
* @param command the command to start
* @return this trigger, so calls can be chained
*/
Trigger WhileTrue(Command* command);
/**
* Starts the given command when the condition changes to `true` and cancels
* it when the condition changes to `false`. Moves command ownership to the
* button scheduler.
*
* <p>Doesn't re-start the command if it ends while the condition is still
* `true`. If the command should restart, see RepeatCommand.
*
* @param command The command to bind.
* @return The trigger, for chained calls.
*/
Trigger WhileTrue(CommandPtr&& command);
/**
* Starts the given command when the condition changes to `false` and cancels
* it when the condition changes to `true`.
*
* <p>Doesn't re-start the command if it ends while the condition is still
* `true`. If the command should restart, see RepeatCommand.
*
* <p>Takes a raw pointer, and so is non-owning; users are responsible for the
* lifespan of the command.
*
* @param command the command to start
* @return this trigger, so calls can be chained
*/
Trigger WhileFalse(Command* command);
/**
* Starts the given command when the condition changes to `false` and cancels
* it when the condition changes to `true`. Moves command ownership to the
* button scheduler.
*
* <p>Doesn't re-start the command if it ends while the condition is still
* `false`. If the command should restart, see RepeatCommand.
*
* @param command The command to bind.
* @return The trigger, for chained calls.
*/
Trigger WhileFalse(CommandPtr&& command);
/**
* Toggles a command when the condition changes from `false` to `true`.
*
* <p>Takes a raw pointer, and so is non-owning; users are responsible for the
* lifespan of the command.
*
* @param command the command to toggle
* @return this trigger, so calls can be chained
*/
Trigger ToggleOnTrue(Command* command);
/**
* Toggles a command when the condition changes from `false` to `true`.
*
* <p>Takes a raw pointer, and so is non-owning; users are responsible for the
* lifespan of the command.
*
* @param command the command to toggle
* @return this trigger, so calls can be chained
*/
Trigger ToggleOnTrue(CommandPtr&& command);
/**
* Toggles a command when the condition changes from `true` to the low
* state.
*
* <p>Takes a raw pointer, and so is non-owning; users are responsible for the
* lifespan of the command.
*
* @param command the command to toggle
* @return this trigger, so calls can be chained
*/
Trigger ToggleOnFalse(Command* command);
/**
* Toggles a command when the condition changes from `true` to `false`.
*
* <p>Takes a raw pointer, and so is non-owning; users are responsible for the
* lifespan of the command.
*
* @param command the command to toggle
* @return this trigger, so calls can be chained
*/
Trigger ToggleOnFalse(CommandPtr&& command);
/**
* Composes two triggers with logical AND.
*
* @return A trigger which is active when both component triggers are active.
*/
Trigger operator&&(std::function<bool()> rhs) {
return Trigger(m_loop, [condition = m_condition, rhs = std::move(rhs)] {
return condition() && rhs();
});
}
/**
* Composes two triggers with logical AND.
*
* @return A trigger which is active when both component triggers are active.
*/
Trigger operator&&(Trigger rhs) {
return Trigger(m_loop, [condition = m_condition, rhs] {
return condition() && rhs.m_condition();
});
}
/**
* Composes two triggers with logical OR.
*
* @return A trigger which is active when either component trigger is active.
*/
Trigger operator||(std::function<bool()> rhs) {
return Trigger(m_loop, [condition = m_condition, rhs = std::move(rhs)] {
return condition() || rhs();
});
}
/**
* Composes two triggers with logical OR.
*
* @return A trigger which is active when either component trigger is active.
*/
Trigger operator||(Trigger rhs) {
return Trigger(m_loop, [condition = m_condition, rhs] {
return condition() || rhs.m_condition();
});
}
/**
* Composes a trigger with logical NOT.
*
* @return A trigger which is active when the component trigger is inactive,
* and vice-versa.
*/
Trigger operator!() {
return Trigger(m_loop, [condition = m_condition] { return !condition(); });
}
/**
* Creates a new debounced trigger from this trigger - it will become active
* when this trigger has been active for longer than the specified period.
*
* @param debounceTime The debounce period.
* @param type The debounce type.
* @return The debounced trigger.
*/
Trigger Debounce(units::second_t debounceTime,
frc::Debouncer::DebounceType type =
frc::Debouncer::DebounceType::kRising);
/**
* Returns the current state of this trigger.
*
* @return A bool representing the current state of the trigger.
*/
bool Get() const;
private:
/**
* Adds a binding to the EventLoop.
*
* @param body The body of the binding to add.
*/
void AddBinding(wpi::unique_function<void(bool, bool)>&& body);
frc::EventLoop* m_loop;
std::function<bool()> m_condition;
};
} // namespace frc2

View File

@@ -0,0 +1,198 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#pragma once
#include <functional>
#include <string>
#include <string_view>
#include <utility>
#include <frc/Timer.h>
#include <frc/sysid/SysIdRoutineLog.h>
#include "frc2/command/CommandPtr.h"
#include "frc2/command/Subsystem.h"
namespace frc2::sysid {
using ramp_rate_t = units::unit_t<
units::compound_unit<units::volt, units::inverse<units::second>>>;
/** Hardware-independent configuration for a SysId test routine. */
class Config {
public:
/// The voltage ramp rate used for quasistatic test routines.
ramp_rate_t m_rampRate{1_V / 1_s};
/// The step voltage output used for dynamic test routines.
units::volt_t m_stepVoltage{7_V};
/// Safety timeout for the test routine commands.
units::second_t m_timeout{10_s};
/// Optional handle for recording test state in a third-party logging
/// solution.
std::function<void(frc::sysid::State)> m_recordState;
/**
* Create a new configuration for a SysId test routine.
*
* @param rampRate The voltage ramp rate used for quasistatic test routines.
* Defaults to 1 volt per second if left null.
* @param stepVoltage The step voltage output used for dynamic test routines.
* Defaults to 7 volts if left null.
* @param timeout Safety timeout for the test routine commands. Defaults to 10
* seconds if left null.
* @param recordState Optional handle for recording test state in a
* third-party logging solution. If provided, the test routine state will be
* passed to this callback instead of logged in WPILog.
*/
Config(std::optional<ramp_rate_t> rampRate,
std::optional<units::volt_t> stepVoltage,
std::optional<units::second_t> timeout,
std::function<void(frc::sysid::State)> recordState)
: m_recordState{std::move(recordState)} {
if (rampRate) {
m_rampRate = rampRate.value();
}
if (stepVoltage) {
m_stepVoltage = stepVoltage.value();
}
if (timeout) {
m_timeout = timeout.value();
}
}
};
class Mechanism {
public:
/// Sends the SysId-specified drive signal to the mechanism motors during test
/// routines.
std::function<void(units::volt_t)> m_drive;
/// Returns measured data (voltages, positions, velocities) of the mechanism
/// motors during test routines.
std::function<void(frc::sysid::SysIdRoutineLog*)> m_log;
/// The subsystem containing the motor(s) that is (or are) being
/// characterized.
frc2::Subsystem* m_subsystem;
/// The name of the mechanism being tested. Will be appended to the log entry
/// title for the routine's test state, e.g. "sysid-test-state-mechanism".
std::string m_name;
/**
* Create a new mechanism specification for a SysId routine.
*
* @param drive Sends the SysId-specified drive signal to the mechanism motors
* during test routines.
* @param log Returns measured data of the mechanism motors during test
* routines. To return data, call `Motor(string motorName)` on the supplied
* `SysIdRoutineLog` instance, and then call one or more of the chainable
* logging handles (e.g. `voltage`) on the returned `MotorLog`. Multiple
* motors can be logged in a single callback by calling `Motor` multiple
* times.
* @param subsystem The subsystem containing the motor(s) that is (or are)
* being characterized. Will be declared as a requirement for the returned
* test commands.
* @param name The name of the mechanism being tested. Will be appended to the
* log entry * title for the routine's test state, e.g.
* "sysid-test-state-mechanism". Defaults to the name of the subsystem if
* left null.
*/
Mechanism(std::function<void(units::volt_t)> drive,
std::function<void(frc::sysid::SysIdRoutineLog*)> log,
frc2::Subsystem* subsystem, std::string_view name)
: m_drive{std::move(drive)},
m_log{log ? std::move(log) : [](frc::sysid::SysIdRoutineLog* log) {}},
m_subsystem{subsystem},
m_name{name} {}
/**
* Create a new mechanism specification for a SysId routine. Defaults the
* mechanism name to the subsystem name.
*
* @param drive Sends the SysId-specified drive signal to the mechanism motors
* during test routines.
* @param log Returns measured data of the mechanism motors during test
* routines. To return data, call `Motor(string motorName)` on the supplied
* `SysIdRoutineLog` instance, and then call one or more of the chainable
* logging handles (e.g. `voltage`) on the returned `MotorLog`. Multiple
* motors can be logged in a single callback by calling `Motor` multiple
* times.
* @param subsystem The subsystem containing the motor(s) that is (or are)
* being characterized. Will be declared as a requirement for the returned
* test commands. The subsystem's `name` will be appended to the log entry
* title for the routine's test state, e.g. "sysid-test-state-subsystem".
*/
Mechanism(std::function<void(units::volt_t)> drive,
std::function<void(frc::sysid::SysIdRoutineLog*)> log,
frc2::Subsystem* subsystem)
: m_drive{std::move(drive)},
m_log{log ? std::move(log) : [](frc::sysid::SysIdRoutineLog* log) {}},
m_subsystem{subsystem},
m_name{m_subsystem->GetName()} {}
};
/**
* Motor direction for a SysId test.
*/
enum Direction {
/// Forward.
kForward,
/// Reverse.
kReverse
};
/**
* A SysId characterization routine for a single mechanism. Mechanisms may have
* multiple motors.
*
* A single subsystem may have multiple mechanisms, but mechanisms should not
* share test routines. Each complete test of a mechanism should have its own
* SysIdRoutine instance, since the log name of the recorded data is determined
* by the mechanism name.
*
* The test state (e.g. "quasistatic-forward") is logged once per iteration
* during test execution, and once with state "none" when a test ends. Motor
* frames are logged every iteration during test execution.
*
* Timestamps are not coordinated across data, so motor frames and test state
* tags may be recorded on different log frames. Because frame alignment is not
* guaranteed, SysId parses the log by using the test state flag to determine
* the timestamp range for each section of the test, and then extracts the motor
* frames within the valid timestamp ranges. If a given test was run multiple
* times in a single logfile, the user will need to select which of the tests to
* use for the fit in the analysis tool.
*/
class SysIdRoutine : public frc::sysid::SysIdRoutineLog {
public:
/**
* Create a new SysId characterization routine.
*
* @param config Hardware-independent parameters for the SysId routine.
* @param mechanism Hardware interface for the SysId routine.
*/
SysIdRoutine(Config config, Mechanism mechanism)
: SysIdRoutineLog(mechanism.m_name),
m_config(config),
m_mechanism(mechanism),
m_recordState(config.m_recordState ? config.m_recordState
: [this](frc::sysid::State state) {
this->RecordState(state);
}) {}
frc2::CommandPtr Quasistatic(Direction direction);
frc2::CommandPtr Dynamic(Direction direction);
private:
Config m_config;
Mechanism m_mechanism;
units::volt_t m_outputVolts{0};
std::function<void(frc::sysid::State)> m_recordState;
frc::Timer timer;
};
} // namespace frc2::sysid