Programming triggers for joystick switches

I’m working as a (new) mentor for our school’s robotics group. I worked with the team a little last year but we never got past more than the ability to drive. Over the summer, I put together a Romi robot and can drive it but I’m trying to program a button to turn on one of the lights just to get a basic understanding. From what I read, it seems like we should be using triggers to respond to button pushes. In looking at last year’s programming, there is a section on “Binding Commands to Triggers” In it they have examples of generic HID, Xbox, PS4 and Joystick using the form
CommandXboxController exampleCommandController = new CommandXboxController(1);
to create the controller and then
Trigger xButton = exampleCommandController.x()
to create the trigger.

In the Romi code they have

private final Joystick m_controller = new Joystick(1);

To use triggers, should I just change this line to

private final CommandJoystick m_controller = new CommandJoystick(1);
and put the trigger below it
Trigger xButton = m_controller.x() ? or Trigger xButton = m_controller.x()

Also what is the x above? Is it just the number of the button or does it follow the labeling on the joystick? Is it different for each instance (HID, xbox, ps4, joystick)?

Sorry for newbie questions but I just can’t quite figure this out and I’d appreciate any help I can get.

Thanks

CommandJoystick has different methods, and doesn’t have an x() method for the “x button” of the controller. It also doesn’t have any button method other than top() and trigger() (button). You may need to look to CommandGenericHID and use the method button(int) with int being the button number. If you don’t know the number, you can usually plug into the driver station and on the joystick page count the position it shows up at.

We use a generic joystick object for our custom button box which works a lot like a generic joystick. Here is how we declare our joystick.

private Joystick operatorJoystick = new Joystick(2);

Then when we configure our button bindings we declare our buttons like this:

    joystickButton operator1 = new JoystickButton(operatorJoystick, 1);
    JoystickButton operator2 = new JoystickButton(operatorJoystick, 2);
    JoystickButton operator3 = new JoystickButton(operatorJoystick, 3);
    JoystickButton operator4 = new JoystickButton(operatorJoystick, 4);
    JoystickButton operator5 = new JoystickButton(operatorJoystick, 5);
    JoystickButton operator6 = new JoystickButton(operatorJoystick, 6);
    JoystickButton operator7 = new JoystickButton(operatorJoystick, 7);
    JoystickButton operator8 = new JoystickButton(operatorJoystick, 8);
    JoystickButton operator9 = new JoystickButton(operatorJoystick, 9);
    JoystickButton operator10 = new JoystickButton(operatorJoystick, 10);
    JoystickButton operator11 = new JoystickButton(operatorJoystick, 11);
    JoystickButton operator12 = new JoystickButton(operatorJoystick, 12);

    Trigger coneTrigger = new Trigger(s_StateController::isConeMode);
    Trigger cubeTrigger = new Trigger(s_StateController::isCubeMode);

Then we use the button bindings like this:

    operator1.onTrue(new InstantCommand(() -> s_Intake.runIntake()));
    operator1.and(intakeSensorTrigger).onTrue(new InstantCommand(() -> s_Intake.stopIntake()));

    operator1.onFalse(new InstantCommand(() -> s_Intake.stopIntake()));
    operator2.onTrue(new InstantCommand(() -> s_Intake.hingeTo(Constants.IntakeConstants.hingeDown)));

    operator7.onTrue(new SetCubeMode(s_LED));
    operator8.onTrue(new SetConeMode(s_LED));

    operator9.and(coneTrigger).onTrue(new HomePositionCone());
    operator10.and(coneTrigger).onTrue(new ArmHigh());
    operator11.and(coneTrigger).onTrue(new ArmMedium());
    operator12.and(coneTrigger).onTrue(new ArmLow());

We used the driver station on the controller menu to determine what each button’s number was.
Included some different examples of the different ways we used button bindings to call instant commands and some actual commands, as well as when in junction with some customer triggers.

Hope this is similar enough to what you are trying to do.

3 Likes

Keep asking questions, I sure wish I had asked more when I started

1 Like

Thanks for all the replies. I now have some follow-on questions.

I may be missing something but in the 2023 changes write-up there is the following statement

" Trigger and Button methods were renamed to be consistent and Button class deprecated."

I took this to mean we should be switching to Triggers vs Buttons which is why I was trying to use triggers with Joystick. We have the Logitech Extreme 3D PRO joystick and it seems to have lots of buttons that could be used. Will we have to do something like RICKMASTER shows to use all the buttons (that seems to not follow the guidelines of deprecating buttons) or be better off switching to CommandGenericHID?

If we switch to CommandGenericHID what are the downsides of doing that vs using the approach that RICKMASTER uses with his design?

(Please remember that we’re still at the point of driving only and so are not familiar with any add-ons to control other things i.e. babes in the woods.)

Thanks for any thoughts people have on this.

“Still learning the basics” will be my mantra for some time :slight_smile:

None; it’s just syntactic sugar. It does the same thing under the hood.

Modern command-based has a lot of syntactic sugaring like this, because without it Java rapidly gets very verbose.

1 Like

I guess I’m still lost. If I use CommandGenericHID,I would create a controller with

private final CommandGenericHID m_controller = new CommandGenericHID(prot:0);

What is the syntax for declaring a Trigger using button 1 on the CommandGenericHID controller.

I assume something like

private final Trigger B1 but I get lost on how to link a button to m_controller

I’m sure I’m missing something obvious but if someone could give the complete set of statements to set up a trigger like this, Id appreciate it

CommandGenericHID has methods that return the Trigger instances - you do not need to declare the trigger yourself, nor store the trigger locally in a field (so, you can do away with the private final Trigger entirely).

You can use CommandGenericHID to do trigger bindings entirely inline without ever using the new keyword - this saves a lot of visual clutter. The functionality is exactly the same as if you had constructed Triggers manually.

I guess I’m still lost. I’d like an example of running a command based on a trigger for one of the buttons on a GenericHID device. Or an example of the same thing for a Joystick or Xbox. Sorry to be such a newbie but Java and I (maybe just I ) need a translator.

Thanks

ok so do what your asking assuming a CommandGenericHID you could do

CommandGenericHID m_controller = new CommandGenericHID(0);
m_controller.x().ontrue(soAndSoCommand);

this will run soAndSoCommand whenever the button x on your generic HID is pressed.

you can also use other functions instead of .ontrue() such as .onfalse(), or .whiletrue(). .whiletrue() runs the command as long as the button is pressed and stops it when it is let go.

You might find this page I wrote useful.

2 Likes

.x() isn’t available for CommandGenericHID, since that class doesn’t know anything about the buttons. It is availible for CommandXboxController. For CommandGenericHID, instead you would do button(1) or whatever button number you want.

Ah true. Tried to go generic and failed… thanks for pointing that out

If I understand this correctly, I should do something like

private final CommandGenericHID m_controller = new CommandGenericHID(0);
m_controller.button(1).ontrue(new PrintCommand(“Button A Pressed”));

(I took the new PrintCommand(“Button A Pressed”) from the Romi Trigger for using the switches on the Romi board as triggers)

Trigger onboardButtonA = new Trigger(m_onboardIO::getButtonAPressed);
onboardButtonA
.onTrue(new PrintCommand(“Button A Pressed”))
.onFalse(new PrintCommand(“Button A Released”));

I tried that and VS doesn’t seem to like that. I puts red squigglies under
the dot before button, under the dot before ontrue and under the last ).

With just the line

private final CommandGenericHID m_controller = new CommandGenericHID(0);

the Romi runs just fine but it doesn’t like the line trying to do the print.

Sorry to keep asking questions but I’m still lost in the weeds on this. Thanks for your patience.

where are you putting the button bindings? (the whatever.onTrue() or whatever.onFalse()) they need to be inside a function such as the configure button bindings in the robotContainer.java. The name doesn’t matter as long as its being called and isn’t in the main class where you’re defining your variables.

oh also you need to split this

onboardButtonA
.onTrue(new PrintCommand(“Button A Pressed”))
.onFalse(new PrintCommand(“Button A Released”));

into this

onboardButtonA.onTrue(new PrintCommand(“Button A Pressed”))
onboardButtonA.onFalse(new PrintCommand(“Button A Released”));

You’re correct about the need to put the binding code in the right scope, but chaining trigger binding calls is totally valid.

First I guess I should never have included the large print section of my question. That was to simply show what I basically wanted to do with the joystick buttons rather than the onboard buttons.

In your answer above

" CommandGenericHID has methods that return the Trigger instances - you do not need to declare the trigger yourself, nor store the trigger locally in a field (so, you can do away with the private final Trigger entirely)."

I took that to mean I could do something like

m_controller.“some button reference”.ontrue(soAndSoCommand);

and that would run “soAndSoCommand”

and not require a Trigger declaration. I just don’t know the exact form of the “some button reference”.

The code in my post about Trigger onboardButtonA in bold is in robotContainer.java and works (it’s in the original code for the Romi.) I was just trying to move the command

“new PrintCommand(“Button A Pressed”)”

into a button trigger in CommandGenericHID.

The examples I’ve seen about triggers show things like

CommandGenericHID m_controller = new CommandGenericHID(0);
m_controller.x().ontrue(soAndSoCommand);

So I assumed putting them together where m_controller is created would be OK

Hope this better explains what I am trying to do

Thanks

This assumption is what’s tripping you up. You can declare a member variable in an ambient class scope, but to do anything with it you need to be in a function or constructor scope.

ah neat I’ll make good use of that

Well I moved the “m_controller.“some button reference”.ontrue(soAndSoCommand);”
into the “private void configureButtonBindings()” function and it will reflect the button1 on and off in the print statements like this

m_controller.button(1).onTrue(new PrintCommand(“Button 1 Pressed”));
m_controller.button(1).onFalse(new PrintCommand(“Button 1 Released”));

I would like to be able to toggle an IO port something like the following

 m_controller.button(2).onTrue(m_onboardIO.setYellowLed(false));

but VS doesn’t like that and gives a message about
“The method onTrue(Command) in the type Trigger is not applicable for the arguments (void)”

The statement “m_onboardIO.setYellowLed(false);” runs just fine on a line by itself so I’m missing something.

Thanks for getting me this far and if you can help with this, it would be much appreciated.

Also this is from the ROMI project if I didn’t mention that.