We have a command that is the default command for a subsystem. It Requires() that subsystem in its constructor. We have another new command that we want to take over the same subsystem for a while. It also Requires() the subsystem. We’ve created a button and attached it to the command with WhileHeld().
The expectation is that when the button is pushed in, the new command will be launched, the default command will have its Interrupted() method called and it will shut down, leaving the new command running until the button is released. When the button is released, the new command should be Interrupted(), and the default command rescheduled.
However, when we hold the button, the second command’s Initialize() runs and the Execute() runs periodically. But the Execute() of the default command continues to run periodically and its Interrupted() method is never called. The SmartDashboard continues to show the original command as the Subsystem’s executing command.
We checked the default commands IsInterruptable() flag, and it is true. We’ve tried using WhenPushed() on the button. We’ve tried giving the subsystem no default command, and starting the first command manually. None of these things altered the behavior.
I’m stumped. Any ideas on how to continue to troubleshoot this issue?
If the new command is returning false for IsFinished () as you mentioned, then I would look for something that is restarting the original command repetetively. Just being the default command should not do this unless the entire subsystem is going through a restart. Since there is no priority here, any new command that requires the subsystem could create a fallback to the original default command and have the whole sequence start over.
What I am interested in seeing is your Interrupted function. Are you calling “End()” in it? If not, the commands won’t end when interrupted, as the interrupted function being called does not do anything by itself unless you have set up the function to actually call the End function.
Another tactic here is to create a new program with one subsystem and two commands as you describe. Put print statements in each at relevant points. See if you get the behavior you describe. Easy to post as an example to discuss.
Yes, it does call End(), but the scheduler shouldn’t care whether you call End() or not. Interrupted() could include all the code from End() or an alternate version of the code from End() for wrapping up what your command is doing. Actually, other than the Requires() in the constructor, and the return from IsFinished(), the scheduler doesn’t really care what you do in your command methods, as long as you exit them in a reasonable timeframe. End() and Interrupted() both could be empty as the queue line during alliance selection.
Another tactic here is to create a new program with one subsystem and two commands as you describe. Put print statements in each at relevant points. See if you get the behavior you describe. Easy to post as an example to discuss.
A good suggestion that we didn’t take the time for. We embedded display code within the methods of the code to watch what was going on. In order to get the functionality, we worked around the problem by embedding the code in the original default command and implemented a state machine to choose the behavior we wanted within that command. Switching commands would have been more straightforward, but this worked.
Once the season is over, and we have time for offseason research, we’ll definitely play with this.
We are successfully using this technique to allow the driver to select which end of the robot is the “front”. Under normal circumstances the gear manipulator is the front but while the trigger is held the fuel pickup/climber becomes the front.
Here is how the two commands are set up:
Command: DriveWithJoystick
DriveTrain default command
Requires: DriveTrain
IsFinished(): returns False
End(): Sets motor speed to zero
Interrupted(): Calls End()
Command: DriveWithJoystickReversed
Driver joystick trigger button - while held
Requires: DriveTrain
IsFinished(): returns False
End(): Sets motor speed to zero
Interrupted(): Calls End()
My instinct is that the default command is not calling End() from the Interrupted() method.
PS We advised the driver to come to a stop before switching the front after popping a rather impressive wheelie when he pulled the trigger while driving at full speed