So this is what I understand about subsystems. You put methods in subsystems that you can call from robotcontainer. For instance, you can create an ‘intakeDown’ method, a ‘runIntakeForward’ method, and a ‘homeIntake’ command. Then, in Robot Container, you would bind these three methods to a button press, like:
IntakeDown - lowers the intake to a set position
runIntakeFoward - runs the intake forward
homeIntake - a runonce method that homes the intake and stops the rollers when the button is released
Pseudocode in Robot Container
whileTrue runIntakeForward and intakeDown else homeIntake
So, first I’d like to know - are we structuring this in a standard, or best practice manner?
Next, we have a question about sensors. We have various sensors. Let’s consider an encoder that gives us shooter position. We need to use this sensor in both the shooter subsystem to verify the shooter is in the right position, AND in the intake subsystem to make sure the shoot and the intake never occupy the same physical space.
I assume best practice is to create a class that contains all my sensors, then somehow pull their values from the class into a subsystem. But I’m at a bit of a loss what the best way is to do that.
We use the subsystems as hardware abstraction and commands as orchestration. So, the subsystems provide access to the sensors, motors, etc. with simple methods like “deployIntake()”. However, we use commands to actually “command” the subsystem to do something or inquiry the state of a subsystem (such as sensor value, current shooter speed, etc.) and then do something.
In the robotcontainer you map the commands to joysticks, etc.
Write your commands as factory methods in the subsystem and you can capture them from the enclosing scope.
If you need sensor input from multiple subsystems, then the command should be defined at a scope where both subsystems are visible (eg RobotContainer) or else the sensor state needs to be plumbed some other way.
Only if it requires access to multiple subsystems. Otherwise, keep it in the scope of a single subsystem.
What we do is have all of the subsystems be public on the RobotContainer class so all commands will be able to check the sensors, etc. on all subsystems. IMHO this just makes everything a lot simpler for students learning programming.
This would look somthing like: RobotContainer.m_shooter.isClear();
Example from last year… Our grabber would grab cone when the sensor triggered.
But depending on what you are doing would probably want to compose a command group something like… Command deployIntake = new WaitShooterToClear().andThen(new DeployIntake());
and you would create your WaitShooterToClear() command to not finish until the sensor said it was clear… once that command ends it does the next command which would deploy the intake.
(My syntax is probably off some, but should be close!)
class MySubsystem {
CANSparkMax mySparkMax = ...;
public Command getDoSomething(double speed) {
return run(() -> {
mySparkMax.set(speed);
});
}
}
SUUUUPER contrived, but this shows the capturing that I believe @Oblarg was referring to. In essence, you return your “command” inline instead of a separate class, and it will allow it to directly use objects scoped to the subsystem class
Commands can require multiple subsystems. I would make a command to control the entire gamepiece handling pathway, which takes the intake, shooter, and presumably loader/indexer subsystems. Then, the command can provide the interlock of only allowing lowerIntake to be called when the encoder is at the right place.