Synchronizing commands using timedRobot? (Java)


#1

Hello, I am wondering how I can program two methods to run simultaneously when I press a button on the Xbox controller.


#2

If both commands don’t require the same subsystem, you can create an instance of the button on the controller and do:
myButton.whenPressed(new Command1());
myButton.whenPressed(new Command2());
Where Command1 and Command2 are the two commands you want to run at the same time. This is answering the question posed in your title. Running methods at the same time is a bit different and requires spawning two threads, one for each method.


#3

Use a command group and bind that to the button’s whenPressed method:

Custom command group

public class YourCommand extends CommandGroup {
  public YourCommand() {
    addParallel(new Command1());
    addParallel(new Command2());
  }
}

OI.java

JoystickButton button = new JoystickButton(<button num>);
button.whenPressed(new YourCommand());

#4

There is no OI.java file in the timedRobot class. How do I do what you said in the robot.java file?


#5

I suggest reading through the command-based documentation: http://wpilib.screenstepslive.com/s/currentCS/m/java/c/88893

If you don’t want to make an OI class, put that code in robotInit


#6

I suggest using a command group instead of using a timedRobot class or myButton approach. They are very easy to use, in both Java and C++. There is no need for it to be put in robotInit, you just need to add it to a button in OI.


#7

In timedRobot, I can’t do the command group thing, I have not been able to figure it out. I am wondering however if doing this would work:

if(XboxController.getAButton){
moveElevToTarget(…);
}
if(XboxController.getAButton){
moveWristToTarget(…);
}

Would the above code run at the same time since when the A button is held, both if statements become true.


#8

Yes the above code would run but that’s not really the best solution. Below I have instructions that meet you halfway between what you want to do and command based programming:

Right click on the lowest level directory ) where the robot file is located) in visual studio and click the option at the bottom to create new class/command.

At the top select command and then name it something like, MoveWrist.

Now that command will exist as a file on the left. You can open it and in the execute method, add the code that moves the wrist. In the isFinished method, use an if statement or some other logic to “return true;” when the command is finished doing what it needs to do and return false otherwise.

Repeat all this for the other command.

Now in the robot class create a new JoystickButton object:
JoystickButton aButton = new JoystickButton(myXboxControllerObject, 1);

You can replace 1 with 2 for b, 3 for x, and 4 for y

Now in robotInit, you can add the lines

aButton.whenPressed(new WristCommand());
aButton.whenPressed(new ElevatorCommand());

This will now run those commands whenever the button is pressed. This is absolutely not the proper way to do it, but it is easier than learning the intricacies of command based programming for the robot. That being said, I would extremely highly recommend reading the command based programming resources that are available.

Please ignore the steps I gave and just read through this which explains how command based is supposed to be done: https://wpilib.screenstepslive.com/s/4485/m/13809/c/88893


#9

Yea, I would rather do this than switch to command based programming in the middle of the season when we have a lot of it already programmed.

In the command class that I have to create, do I have to redefine the motors to the talon/victor objects I created in the Robot.java file? Also, since we are using motion magic to control our elevator and wrist, do I configure those values in the Robot.java or in the command file?


#10

Make everything in robot public static and then in the command you can access everything defined in robot using Robot.mySpeedController

Keep in mind that if you have other things running in your regular robot loop that also use the same speed controller, you may have an issue where the command and your code in autonomous/teleop periodic compete to control the same thing. If this is the case, you will need to keep track of if the commands are running. You can do this by creating instances of the commands in the robot class:
WristCommand wristCommand = new WristCommand();
And then replacing the “new WristCommand()” in the button whenPressed assignment with simply “wristCommand”

Then you can have an if statement that goes like this:
If (wristCommand.isRunning()) {
//command is running do not control its speed controllers
} else {
//command is not running, feel free to set values for its speed controllers
}

Additionally, in teleopPeriodic and autonomousPeriodic you need to make sure you have the following like somewhere in the methods:
Scheduler.getInstance().run();
This will run any active commands.


#11

Ok, thank you. Is there a way in the command.java file for me to pass a parameter through the command? I want to pass a parameter and use that for the motion magic setpoint.

In the command file:

public class MoveWrist extends Command {
double setpoint = 0.0;
public MoveWrist(double target) {
setpoint = target;
}
@Override
protected void execute() {
Robot.wristMaster.set(ControlMode.MotionMagic, setpoint);
}
}

and then in the robot file
aButton.whenPressed(new MoveWrist(setpoint));
Would that work for passing a parameter through the command?

I wasnt able to pass through a parameter if I created an instance of the wristCommand in the robot class. The parameter would be called when I created it in the robot class. I want it so when I press aButton, it goes to a preset position and when I press bButton, it goes to another preset position.


#12

This would work. You could also do this:

WristCommand wristToPosA = new WristCommand(positionA);

WristCommand wristToPosB = new WristCommand(positionB);

aButton.whenPressed(wristToPosA);
bButton.whenPressed(wristToPosB);

And then in the periodic methods:

If (wristToPosA.isRunning() || wristToPosB.isRunning) {
//Something is running let the commands handle everything
} else {
//nothing is running. You have manual code over everything here
}

Since you will be having two instances of the command, you should make sure that you cancel the old instance if it’s running when you start a new one. For this reason you should also add:

aButton.cancelWhenPressed(wristToPosB);
bButton.cancelWhenPressed(wristToPosA);

Normally this would be handled automatically is a true command based robot. But in this case, these two lines need to be added. In order for this to work, you need to create the instances wristToPosA and wristToPosB instead of just creating an instance in the whenPressed methods.


#13

Thank you very much for your help. I appreciate it.

I have another question: Do I still need to add Scheduler.getInstance().run();? Do I still need to make the isFinished method turn true when the command is done or can I leave the isFinished to always false so the motion magic always runs?


#14

You definitely need the scheduler run code in the periodic methods. As for isFinished. If you don’t have it, the command will just run the execute until the command is canceled. In the case we talked about above, this would happen to the “a” command when the “b” command is pressed and vice versa. If you do not have interest in controlling the wrist manually at any point, and you just want motion magic to be in control the entire match, than this would be fine. Additionally, if you want one of the commands to run right when the robot gets enabled, you can execute wristToPosA.start() for example and the command will run even before someone presses a button. This is what I’d recommend if you don’t plan on having the commands terminate themselves using isFinished as you should always have something (e.g. one of your commands) telling the speed controllers what they need to do.


#15

@Dario_Zac I managed to find your code on github. You should be setting button.whenPressed()/cancelWhenPressed() actions in robotInit not in the periodic methods.


#16

Oh ok thank you. We will try leaving the isFinished to always false because we want motion magic to always run so the wrist/elev stays in position.