I think this is an issue of Command design, not of the overall model. If there are two Commands that interact in weird ways if used improperly, I try to contain their use cases in CommandGroups that can guarantee that they will interact as desired. This isn't always feasible, but it can be much more readable than a complex redesign to handle the weirdness.
If you're using a CommandGroup, this isn't a problem. CommandGroups implicitly require() all subsystems that the Commands in them require. This year our launcher requires some pretty complex sequences, but by using CommandGroups and setting one as the default command, we were able to automate all but a very small part of it.
This is a situation where running the wheel control in a different thread (eg. through a PIDController/PIDSubsystem) would be helpful. Last year, our Shoot command looked like this:
Code:
addSequential(new SpinUp(speed));
addSequential(new DeployDisk());
While this ran, even after SpinUp ended, the wheel kept spinning. Using a PIDSubsystem also let us add a safety feature: the default command waited 5 seconds, then spun the wheel down, in case it hadn't been done manually.
If you are suffering from a lot of boiler-plate, make some classes to inherit from! For example, our code-base includes this class:
Code:
// Does nothing, and keeps doing it forever
public class DoNothing extends Command {
public DoNothing() {}
protected void initialize() {}
protected void execute() {}
protected boolean isFinished() {
return false;
}
protected void end() {}
protected void interrupted() {}
}
This is one of the reasons my team does not use RobotBuilder. It's very good for getting some example code or a base to start from, but as soon as you try to modify anything in a way that the template's writer didn't think of, you're somewhat screwed. Creating the subsystems and declaring all the hardware by hand is not an arduous task, and reduces barriers to any necessary changes.