We are currently building a turret robot that we want the turret to stop at certain positions when a button is pressed. We have wrote the code below to determine what command to run based on what state it is in but it is not working? Anyone have any ideas on how to do this? We are running a command style robot.
private void configureButtonBindings() {
int state = 0;
if (state == 0){
mechButton2.whenPressed(new turnCommand());
state++;
}
else if (state == 1){
mechButton2.whenPressed(new secondTurn());
state++;
}
configureButtonBindings runs once in the RobotContainer constructor. So you can’t put logic in there that needs to execute at runtime. The code that you have will always run turnComand when mechButton2 is pressed, since state will always be 0 at robot startup. There’s a few options.
If it’s as simple as running two different commands, you could use a ConditionalCommand.
If you want to select between a few different commands, you could use a SelectCommand.
Or you could put your logic in the initialize method of a command, and put the logic based on each state in the execute method.
For the first two options, the state should be contained in the turret subsystem and passed to the command with a lambda, so that the current state is captured when the command is scheduled. For the third option, the state could be contained in the command, as long as you’re only making one instance of it or the state is declared static.
As a general “rule”, we try to avoid things that make the drivers remember state. Rather then have the driver press a button several times to get something to move to the right place, have multiple buttons that the driver can press to go to the right position. It makes for less things to remember during the match while there’s a lot going on. We do occasionally break the “rule” but only if the state of the robot is obvious by looking at the robot from an orientation (ie a very large gripper that is either open or closed).
Another way is to make your Turret Subsystem to maintain its own state at all time. Private method that gets initialize to a ‘known state’ (call it state 0). And then each time a command calls the turret, it would look at the state and base on that, do what is needed (and update its own state value to prep for next state). And you can always ‘reset’ the state to whatever state values you need with special “command/calls” into the Turret subsystem.
I put in the SelectCommand and got it working if I manually select which a variable. How would I get it to cycle through all the options. For example start at one, then next would be two, then three, then four…
Heres my code that has it working.
private enum CommandSelector{
ONE,
TWO,
THREE,
FOUR,
FIVE,
SIX
}
private CommandSelector select(){
return CommandSelector.TWO;
}
private final Command m_exampleSelectCommand =
new SelectCommand(
Map.ofEntries(
Map.entry(CommandSelector.ONE, new turnCommand()),
Map.entry(CommandSelector.TWO, new secondTurn())),
this::select);
This is what I added to try to get it to work but to no avail.
private enum CommandSelector{
ONE,
TWO,
THREE,
FOUR,
FIVE,
SIX,
ZERO
}
private CommandSelector select(){
int state = 0;
if (state == 0){
state = state + 1;
return CommandSelector.ONE;
}
else if (state == 1){
state = state + 1;
return CommandSelector.TWO;
}
else {
state = state + 1;
return CommandSelector.ZERO;
}
}
private final Command m_exampleSelectCommand =
new SelectCommand(
Map.ofEntries(
Map.entry(CommandSelector.ZERO, new returnTohome()),
Map.entry(CommandSelector.ONE, new turnCommand()),
Map.entry(CommandSelector.TWO, new secondTurn())),
this::select);
public class Indexer extends SubsystemBase {
private final TalonSRX indexerWheel = new TalonSRX(55);
private final int state = 0;
/**
* Creates a new Indexer.
*/
public Indexer() {
}
public int getState() {
return state;
}
Then in you command, get your state and decide what to do from there
public class TurnOnIntake extends InstantCommand {
private final Intake m_intake;
public TurnOnIntake(Intake intake) {
m_intake = intake;
addRequirements(intake);
}
// Called when the command is initially scheduled.
@Override
public void initialize() {
if(m_intake.getState() == 0) {
// do something if the state is 0
} else {
// do something if the state is not 0
}
}
Since you declare state and set to 0 in the select method, any time it’s called state will be 0. You need to declare state and initialize it outside the select method so it will retain its value.
Sorry for the late reply. If you haven’t figured it out yet, one possible solution to incrementing the state is to create a function in the subsystem that increments the state
public void incrementState() {
state++;
}
or
public void setState(int newState) {
state = newState;
}