Toggle button between two commands

Hello, we are currently attempting to map a button that can toggle between two different commands. Initially, command1 will run. When button is pressed, command1 will cancel, and command2 will run. If the button was to be pressed again, command2 will be paused, and command1 will run.

We can code this in subsystem, but we were wondering if there were any ways to map/code this on Robot Container.

We are currently coding on VS Code,

“edu.wpi.first.GradleRIO” version “2020.2.2”

Yes I’m stuck on this problem too. The only way we can have something remotely similar is having a button held down to run command 1, and when the button is released, command 2 will run. Any help on the toggle would be great. Thanks!

Well… You could make use of the Button Class’s toggleWhenPressed() method. It could do what you are proposing. The big problem though is that if either command, while its running, ever finishes or is interrupted, it would break it and both commands would start being run together instead of flip-flopping since all the toggleWhenPressed() method does is look to see if the command is already scheduled and if it is, cancel it, and if its not, schedule it. You can get around it being interrupted by making sure to specify its not interruptible (which won’t stop the toggleWhenPressed from cancelling it), and you’d probably want to make sure that isFinished() in these commands always returns false. As long as no other commands need the subsystems these two commands do, it would work. Otherwise, check out my not as detailed recommendation at the bottom.

Here is the theoretical code though. Its freehanded and untested.

Command firstCommand = new MyFirstCommand(relevantSubsystem); // We want this already running
firstCommand.schedule(false);                              // so when the Toggle is pressed, it gets interrupted
new JoystickButton(joystick, buttonNum).toggleWhenPressed(firstCommand, false).toggleWhenPressed(new MySecondCommand(relevantSubsystem, false); 
// You NEED to use the SAME Command object here, NOT make a second one. Even though the two objects would be the same Command class, they aren't the same object, so they are scheduled and managed separately. 
// The false being passed to toggleWhenPressed and schedule is the interruptible flag, so they won't be interruptible. 

Though, I’d argue that it may be better to make your own class that extends JoystickButton overrides the toggleWhenPressed method, and somehow keeps track internally on which one was scheduled last instead of just looking at if it is scheduled currently.

Simple way:

  • Have both command1 and command2 require the same subsystem.
  • Make command1 the default command for the subsystem. Make sure it is interruptable so that if another command gets scheduled for the same subsystem, command1 can be interrupted (they are interruptable by default).
  • Use .toggleWhenPressed() to start command2.
  • Make sure that command2 is interruptable so that .toggleWhenPressed can interrupt it (again, they are interruptable by default).

Command1 will run by default; when the button is hit, command2 will start and interrupt command1; when the button is hit again, command2 gets interrupted and the default command (command1) gets started again.

2 Likes

or alternatively, use flags within the command to switch between the two set of functions. you would check the flag state in initialize in the command and switch to the other one from what you read. then you have the two sets of functions, which would have been individual command, that will run depending on how the flag is set.

Thank you for the reply!
I coded what you have instructed me for your first recommendation, and it works. I deployed my code on roboRio, and it works.
Listed below is my code.

private void configureButtonBindings() {

    ExampleCommand firstCommand = new ExampleCommand(m_exampleSubsystem);

    ExampleCommand2 secondCommand = new ExampleCommand2(m_exampleSubsystem);

    firstCommand.schedule(false);

    JoystickButton changeBtn= new JoystickButton(stick, 1);

    changeBtn.toggleWhenPressed(firstCommand, false).toggleWhenPressed(secondCommand, true);

  }

I will attempt to extend JoystickButton class and override the toggleWhenPressed as soon as possible.

I have attempted my best to code what you have stated. It works!

public void modeButton() {

    ExampleCommand firstCommand = new ExampleCommand(m_exampleSubsystem);

    ExampleCommand2 secondCommand = new ExampleCommand2(m_exampleSubsystem);

    m_exampleSubsystem.setDefaultCommand(firstCommand);

    JoystickButton changeBtn= new JoystickButton(stick, 1);

    changeBtn.toggleWhenPressed(secondCommand);

  }

Thank you!

If @fovea1959’s method works for your situation (all same subsystem and no problem making one the default command), I definitely recommend it over the method I stated.

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