Comparison with WPILib’s Commands

Strongback’s command framework is very similar to WPILib command-based framework. Indeed, if you’ve used the WPILib commands in the past, you probably find Strongback’s framework to be easy to grasp — and probably simpler to use.

But while Strongback’s command framework might be similar to that in WPILib, there are definitely some important differences.

Command classes

Both frameworks' concept of a command are very similar. The differences are in the details of how they’re implemented and what this means for your FRC team.

WPILib Commands

When you use WPILib commands, you write a class for each command, and this class extends the edu.wpi.first.wpilibj.command.Command abstract base class. WPILib’s design requires your class do several things:

  • Provide a constructor that calls the superclass' constructor and that calls doesRequire(…​) relay required Subsystem objects.

  • Provide an initialize() method that the framework will call prior to execute(), and the method can perform any one-time initialization logic.

  • Provide an execute() method that contains the logic of your command. The method doesn’t return anything, and may be called multiple times depending upon the isFinished() method.

  • Provide an isFinished() method that tells the framework when the command is complete.

  • Provide an end() method that the framework will call when the command successfully finished, allowing your command to respond if needed.

  • Provide an interrupted() method that the framework will call to let your command know it’s been interrupted.

Additionally, the edu.wpi.first.wpilibj.command.Command base class has a few methods you are expected to use (e.g., doesRequire(…​)) and numerous methods that you can (but shouldn’t) override or call. Most of those methods deal with the command’s lifecycle and state required by WPILib to properly run the command. It even has methods to start() and cancel() the command.

The last two methods make each command know how to execute itself, and they are a big reason why it is very difficult to unit test your command subclasses. The edu.wpi.first.wpilibj.command.Command is so chocked full of things that your tests simply cannot instantiate them withouth staring a good portion of the WPILib system, including those that ultimately require hardware.

Strongback Commands

When we designed Strongback, we took what we learned about using and trying to test WPILib commands and thought we could do better. We wanted to make it easy as possible to write subclasses and, where possible in some simple cases, to not even require custom subclasses. To write a custom command class with Strongback, you must:

  • Provide a constructor that calls the superclass' constructor with requirements and timeout information (if there are any), and optionally call setNotInterruptible() if desired (all commands are interruptible by default).

  • Provide an execute() method that contains the logic of your command and that returns whether the command is completed.

That’s it! Of course, if you want you can override any of the default methods:

  • Optionally override the initialize() method that the framework will call prior to execute(), and the method can perform any one-time initialization logic. The default method does nothing, so you only have to override this if you want different behavior.

  • Optionally override the end() method that the framework will call when the command successfully finished, allowing your command to respond if needed. The default method does nothing, so you only have to override this if you want different behavior.

  • Optionally override the interrupted() method that the framework will call to let your command know it’s been interrupted. The default method does nothing, so you only have to override this if you want different behavior.

The Strongback Command base class has very few methods, no lifecycle state, and does not know how to start or run. Instead, your robot code is responsible for submitting the command for execution, typically via Strongback.submit(Command).

This design makes it very easy to write and test custom command subclasses. For example, here is a complete Command subclass (minus the import statements and JavaDoc):

public class OpenClaw extends Command {
    private final Solenoid solenoid;
    public OpenClaw( Solenoid solenoid ) {
        super(solenoid);
        this.solenoid = solenoid;
    }
    @Override
    public boolean execute() {
        this.solenoid.retract();
        return true;
    }
}

Strongback was designed to use Java 8 features, so you might not even need to write a custom command subclass for all of your commands. If they’re simple enough, you might be able to just pass a lambda expression to one of the Command class' static methods. For example, here is a simpler (albeit more anonymous and less reusable) way to define our previous OpenClaw command:

Solenoid solenoid = ...
Command openClaw = Command.create(()->solenoid.retract());

Other Command class' static methods are available for creating commands that cancel, that pause for a fixed amount of time, or than run lambdas once or multiple times and possibly for a maximum duration.

Requirements

Both frameworks have similar notions of a command requiring some other object(s). And in both frameworks when a command is run, the framework will cancel any previously-started command that required the same object(s).

WPILib Subsystem

With WPILib, commands could state they require one or more edu.wpi.first.wpilibj.command.Subsystem objects. Examples of a subsystem might be a drive train, a claw, or motors on an arm. The WPILib documentation states that all motors should be a part of a subsystem, so you need to write one Subsystem subclass for each of your logical subsystems.

Unfortunately the Subsystem class is not terribly small. It actually has all the state about which command is currently being executed, and it includes methods for communicating with the Network Tables. Despite this, it’s not terribly difficult to write or use Subsystem subclasses. Testing them is more challenging, but that’s mostly because the motors that subsystems are to contain require hardware, and thus aren’t suitable for testing off-robot with simple unit tests.

Strongback 'Requirable'

Strongback, on the other hand, uses a far simpler notion of required objects: ß

, here are a couple of ways to create commands you can

The easiest way to do that is to offer methods that you can sometimes use you can use so that you sometimes s ways where you don’t have to actually

  • Creating command classes - We tried to make it as easy as possible to create subclasses. Where WPILib has separate methods for execute():void and isFinished():boolean, Strongback instead combines them into a single execute():boolean method. Strongback also provides static methods that create commands that pause, commands that run a function one time, commands that cancel any running commands with the same requirements, commands that run a lambda, and commands that execute a function for a maximum period of time.

  • Requirements - Whereas Strongback commands can require any object that implements the Requirable marker interface, WPILib commands can only depend upon edu.wpi.first.wpilibj.command.Subsystem subclasses that are heavyweight. Strongback behaves the same was as WPILib, but all logic is embedded in classes you don’t have to extend or subclass.

  • Running - WPILib ryou call run() on the command, but ghis makes it too difficult

for common activities, like pausing a

, and to also be able to The W`edu.wpi.first.wpilibj.command.Command class requires your subclass override a number of methods for most commands, whereas with Strongback we tried to

Table 1. Windtrainer workouts
Strongback Class WPILib Class Notes

org.strongback.command.Command

edu.wpi.first.wpilibj.command.Command

22-Aug-08

10:24

157

Worked out MSHR (max sustainable heart rate) by going hard for this interval.

22-Aug-08

23:03

152

Back-to-back with previous interval.

24-Aug-08

40:00

145

If you’ve not used either, we think you’ll find it pretty eas But we found the WPILib version to be difficult to use and very difficult to test. Command and CommandGroup

results matching ""

    No results matching ""