Delaying commands in command based?

I’m currently trying to program a wheeled intake that is deployed via pneumatic. I was hoping to be able to deploy and run the intake before retracting then continuing to run the motors for about a second after the deploy command is called. I initially thought to do this via a Thread.sleep() call but was told this would lock the robot code(even though I’m pretty sure each command call can get threaded) my idea is as follows

In Intake subsystem:

   public void stop() {
        retract();
        Thread.sleep(1000);
        m_motor.stopMotor();
    }

Then schedule it as so:

       new JoystickButton(ctl, XboxController.Button.kB.value)
            .whenPressed(() -> m_intake.intake())
            .whenReleased(() -> m_intake.stop());

Would this only cause a sleep to occur for the current command or would this hold up the entire scheduler, including stuff like driving.

Another way which I was sort of able to get working but ran into the issue that while it would delay as intended it wouldn’t allow the command to be rescheduled until the delay was finished(basically the delay command couldn’t be interupted)

FloorIntake:

public class FloorIntake extends CommandBase {

    private final Intake m_intake;

    public FloorIntake(Intake intake) {
        m_intake = intake;
        addRequirements(intake);
    }

    @Override
    public void initialize() {
        m_intake.extend();
    }

    @Override
    public void execute() {
        m_intake.set(IntakeConstants.RPM);
    }
    
    @Override 
    public void end(boolean interrupted) {
        m_intake.retract(); 
    }
     
}

scheduled as so:

  new JoystickButton(ctl, XboxController.Axis.kLeftTrigger.value)
            .whenPressed(m_floorLeftIntake)
            .whenReleased(new InstantCommand(() -> m_leftIntake.retract())
                .andThen(new WaitCommand(1))
                .andThen(() -> m_floorLeftIntake.cancel())
            );

To my knowledge, the command scheduler is still single-threaded, so the sleep call would absolutely lock up the entire robot.

What you’re looking for would seem to be a SequentialCommandGroup, with a WaitCommand as the delay.

2 Likes

You might also find command decorators like withTimeout() useful:

1 Like

Can you clarify in numerical steps what you’re trying to do? I’m confused by what you said here:

So you want to:

  1. Deploy the intake pneumatics
  2. Run the intake motors
  3. Wait for some amount of time (in this case a second)
  4. Do something else not yet spoken of here

If that assumption is true, Fletch’s advice is definitely the simplest way to go. A sequential command group is the way to go.

For your delay, you could either use the .withTimeout() decorator on your run intake motors command, or just insert a WaitCommand(1) in the command sequence.

Definitely this. If you’re trying to make complex logic built on top if commands you already have, command groups should be the first idea you look at. Also, if you haven’t looked at the convenience features section of wpilib’s command based docs, I would recommend doing so. There are a lot of nice command types built into wpilib that help with complex functionality.

2 Likes

https://github.com/rr1706/Control2022/blob/ProtoBot/src/main/java/frc/robot/commands/FloorIntake.java does this look correct, or will this also block the command scheduler

I think that should work, but it hides the sequential command group logic. Why not make a sequential command group with all the steps?

I’ve discussed a bit more with my teammates and we’ve come up with the idea of extending the SequentialCommandGroup class like so

package frc.robot.commands;

import edu.wpi.first.wpilibj2.command.Command;
import edu.wpi.first.wpilibj2.command.SequentialCommandGroup;
import edu.wpi.first.wpilibj2.command.SubsystemBase;
import edu.wpi.first.wpilibj2.command.WaitCommand;

public class DelayedCommandGroup extends SequentialCommandGroup {

    /**
     * Schedule a set of commands with a delay between each except the last
     * 
     * @param delay
     *            Time to wait between each command in seconds
     * @param systems
     *            The required subsystems to hold
     * @param commands
     *            The runnables to add
     */
    public DelayedCommandGroup(int delay, Command[] commands, SubsystemBase[] systems) {
        // Use an indexed for loop here becuase we don't want to add the last command with a delay
        for (int i = 0; i < commands.length - 2; i++) {
            addCommands(commands[i]);
            addCommands(new WaitCommand(delay));
        }

        addCommands(commands[commands.length - 1]);

        for (SubsystemBase system : systems) {
            addRequirements(system);
        }
    }
}

I also think this covers what you mean when you say hiding the sequential command logic

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