Command Based passing data between Subsystems

We are using Command Based Programming and would like to pass position information from SubsystemA to SubsystemB. I would like to use the position of SubSystemA in the Periodic method of SubsystemB as changes. I’m not sure how to pass the information. Any help would be appreciated.

Thanks,

This is what’s known as a “code smell”. That bit of functionality you need to access in both places should live somewhere else instead. However, without knowing what that code/functionality is, I can’t make any suggestions on where it should go.

4 Likes

You have a couple of options here. If SubsystemB needs to use info from SubsystemA, you can pass SubsystemA through the constructor to SubsystemB. If A also needs B, then you cannot do this.

If both require data from each other, you could create a class called SharedABState (or come up with a name that suits it). You would then add methods to change its state and also add getters to get its state.

Alternatively, you could consider combining the subsystems into a single subsystem. For instance, this year we were going to have an IntakeSubsystem and an IndexerSubsystem, but I think we will probably only have an IntakeSubsystem now because of how much both subsystems would need to communicate with each other to make any useful automation of the indexing and spitting out of balls.

4 Likes

We declare all the subsystems in the robot container as public and create a singleton instance of the robot container.

I understand that many will disagree with this approach but it is very practical…

Code looks like…
RobotContainer.getTheRobot().m_<subsystem>

2 Likes

We go a step further and just create static instances of each Subsystem in Robot.java and reference them as “Robot.intake”, etc.

Definitely not the best practice but it’s very practical and for us easier to teach.

Back to the OP, do your subsystems actually need to get information from each other or could you do what you need inside of commands that use both subsystems?

1 Like

As long as the subsystems are decoupled and independent I’m not sure it is a problem. One solution would be to use NetworkTables. That way you are not technically calling one subsystem from another but B can use the input just as it would any other input from sensors or a dashboard.

1 Like

Personally, I would view storing data from one subsystem to another itself as an anti-pattern. Though I could probably think of a case or two where I would find it the better way if I tried. Also note that I don’t say passing this data to anther subsystem. However, any such passing I would do through a Command.

A case like this we dealt with in 2020 with our Infinite Recharge bot was with our Launcher. We had a Camera subsystem that would give us our distance from the goal, and of course the Launcher subsystem which controlled the flywheels. What we did was pass the Launcher subsystem to the command as the required subsystem and then a lambda with the function call to the Camera subsystem as the data the command needed.

ie.

new SetLauncherByDistance(m_launcher, () -> m_camera.getDistanceToGoal())

Then you just need some kind of a distanceToVelocity(double distance) method or piece of code to convert one to the other and use that to set the speed of the launcher. You could write this in the Command itself, or in a subsystem. I think we put this in the Launcher, so the execute looked something like:

void execute() {
  m_subsystem.setVelocity(m_subsystem.distanceToVelocity(m_distance.getAsDouble()));
}

and so I have used data from one subsystem to perform an action on another subsystem.

If you do however just want to store some data from one subsystem to another, and have it run every loop of the scheduler. You can still do it the same way with commands. If I am not mistaken you don’t need to declare any requirements for a command, and If your Command isn’t performing any actions that will change the outputs of the subsystem, I would say it is safe to not add them as requirements. I would personally set it up the same as above with the data from the first subsystem being passed through Lambdas, and the second subsystem itself being passed by reference to call the set methods. Then you can just run it as a PerpetualCommand. I would probably do it in the RobotContainer constructor alongside the subsystem default commands.

ie.

new PerpetualCommand(new PassSubsystemData(m_storeSubsystem, ()->m_retrieveSubsystem.retrieveData(), ()->m_retrieveSubsystem.retrieveMoreData());
1 Like

This is especially useful for a subsystem like StatusLED which needs info from many different subsystems to determine what light pattern to display.

For most other subsystems or commands I try to have the students pass only what other subsystems the acting subsystem needs to access.

Suppliers are very convenient here in our experience.

1 Like

This topic was automatically closed 365 days after the last reply. New replies are no longer allowed.