WhileHeld Command Help

I’m trying to implement WhileHeld in the OI file to trigger a command to start a motor. The problem is once it starts it won’t stop, if I let go of the button that is mapped to the WhileHeld. What I read in previous posts is that you’ll need to put in the interrupt routine to stop the motor. I did that and I’m constantly seeing the motor stuttering. Upon debugging I found that the code was switching between execute() and interrupt() in the command class. I also don’t know whether I should set isFinished() to true or false. The whileHeld button should be ignoring isFinished() right? Anyone have any idea how to implement a hold button logic to start a motor while it’s held and stop it once it’s released? Thanks.

Motors: Unless a watchdog is implimented to stop a motor if it isn’t receiving updates (automatic for Drivetrain objects like DifferentialDrive for example), a motor will continue with the last update it was given. So even if your command stops, if the last thing it told the motor to do was “go forward at 50%” ie motor.set(0.5) it would continue even if the command ended.

Buttons: whileHeld() doesn’t affect how commands work, and doesn’t cause them to ignore isFinished(). What it will do is continue to tell the command to start, as well as cancel() it when you release the button, which counts as an interrupt and will cause interrupted() to be called. I am not sure how the two would conflict if a command was constantly saying it was finished, as well as being told to start every scheduler cycle, I would have to do some looking over the wpilib Scheduler and Command source code.

If it is calling interrupt() over and over then something is causing that. Possibilities I see more often include trying to also start other commands that require() the same subsystem, and calling interrupt() from end() when you have isFinished() returning true.

It would also help if you could post the entirety of your robot’s source code, preferably on a platform like GitHub. This can make tracking down common or even unusual mistakes or errors much easier, and help us, help you.

I looked over the source code, and from what I can tell. If isFinished() returned true while the command is being start()-ed by a whileHeld() the command would process the end() before re-starting. The same is true for interrupt() if a command is interrupted() by another command starting.

Thank you for the replies, it was very informative. I had uploaded our test code in my repo on GitHub

Very plain test code.

A couple of points:

  1. You should probably move the logic from ScoreCargo.interrupted() to ScoreCargo.end() and get rid of your interrupted() override. The base implementation of interrupted() calls end() anyhow.
  2. The way you are allocating your scoreCargo() may be part of the problem. I suggest moving that allocation to a public initialize() method on OI, and calling that from your robotInit() around line 42. You could technically do that inside an OI constructor, but as your project gets more complex having a separate initialize() becomes handy.
1 Like

So I believe I found the problem. I believe its the same thing that @BenBernard is trying to say on his second(2) point.

Buttons: whileHeld() (as well as other triggers like whenPressed() and ToggleWhenPressed()) register themselves with a “buttonScheduler” which is managed by the main Scheduler. So you only need to call whileHeld() once and the scheduler will check the state of that trigger every period when you run the Scheduler.getInstance().run() in your teleopPeriodic() and autonomousPeriodic().

So what’s happening here is you are adding another… and another… and another… of these triggers every time your code calls m_oi.getJoystick2() so what happens is each of those triggers are all trying to start their instance of the ScoreCargo Command. Thus they are constantly trying to interrupt each other, leading to the shuttering you are seeing.

As @BenBernard said, you could move the whileHeld() call to the constructor, or make an initialize() method in OI that you call only once in say robotInit() somewhere after you initialize all your subsystems(otherwise you get other weird behavior or errors).

2 Likes

Thank you @ExploitSage and @BenBernard for the pointers and explanation! I’m starting to understand the scheduler a bit more. I’ll change my and and try it. Also, I’ll read up on the scheduler some more to get a better understanding of it, but you two have more examples or documents about the scheduler besides the one found on the wpilib site?

Honestly, when it comes to understanding how something works at the lower level, I go look at the source code for it, on the WPILIBSuite Github Account. The main two things you need to look at are the Scheduler.run() method and the Command.run() method. Both of those classes are in the command package at the link below:

If you don’t feel you’re ready yet to take the plunge into the source, it is a bit of a step, even if a very useful one, and you just want to learn how to better use the library correctly, more-so than how it works under the hood, check out the Resource Compendium I made for my team. I have tons of links to resources made by other teams and the community like the FRC PDR (Programming Done Right) website, and multiple YouTube Tutorial Series.

@ExploitSage, just wanted to say thanks again. we were able to get our whileheld command working now as well as fixing up some disconnection issues associated with our poor implementation of the command routines.

Have you looked into the whenReleased(command) method? It sounds like that is perhaps what you need to stop the motor as soon as you release the button

Thanks, we definitely needed the WhileHeld function, but we got it working with some pointers from gixxy.

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