Log in

View Full Version : Java Toggle Button


RoastBeefer
29-05-2012, 13:13
Hello, we have a conveyor belt powered by a motor on our bot. We want to press a button and make it run until we press the same button again. We cannot figure out how to do this. Here is what we currently have for our code:

//Conveyor Belt
boolean belt = false;
conveyorMotor.set(0);
if(belt == false){
if(stick.getRawButton(3)){
belt = true;
conveyorMotor.set(1);
}
else if(belt == true){
if(stick.getRawButton(3)){
belt = false;
conveyorMotor.set(0);
}
}

Currently this only turns on the belt while pressed and stops as soon as we let go. I feel like we're taking the totally wrong approach to this. Please help

Mark McLeod
29-05-2012, 13:32
You need an interlock, something along the pseudo-code lines of:


boolean belt = false;
boolean toggle = true;

if (toggle && Button) { // Only execute once per Button push
toggle = false; // Prevents this section of code from being called again until the Button is released and re-pressed
if (belt) { // Decide which way to set the motor this time through (or use this as a motor value instead)
belt= false;
conveyorMotor.set(1);
} else {
belt= true;
conveyorMotor.set(0);
}
} else if(Button == FALSE) {
toggle = true; // Button has been released, so this allows a re-press to activate the code above.
}

artdutra04
29-05-2012, 13:49
Hello, we have a conveyor belt powered by a motor on our bot. We want to press a button and make it run until we press the same button again. We cannot figure out how to do this. Here is what we currently have for our code:

//Conveyor Belt
boolean belt = false;
conveyorMotor.set(0);
if(belt == false){
if(stick.getRawButton(3)){
belt = true;
conveyorMotor.set(1);
}
else if(belt == true){
if(stick.getRawButton(3)){
belt = false;
conveyorMotor.set(0);
}
}

Currently this only turns on the belt while pressed and stops as soon as we let go. I feel like we're taking the totally wrong approach to this. Please helpAre you reinitializing the belt = false every time you execute the following code? If so, every time you run the above code, belt will get set to false and only become true if the button is currently pressed.

Also, to implement a toggling routine in code that takes input from a human, you need a way to slow it down or track previous states. For example, if a toggle function runs once every 10ms, a human pressing a button for 1/2 a second will cause the code to toggle 50 times.

There are two ways to overcome this: timers (only allowing the code to toggle once every ___ ms), or by only toggling the output on button transitions (such as from a not pressed state to a pressed state). Here's a real quick piece of [untested] code that works off the latter principle:

// Run this only once to initialize the variables
boolean beltStatus = false;
boolean previousButton = false;
boolean currentButton = false;

// Run the following code continuously
previousButton = currentButton
currentButton = stick.getRawButton(3);

if (currentButton && !previousButton)
{
beltStatus = beltStatus ? false : true;
}

conveyorMotor.set((double)(beltStatus ? 1 : 0));

This code works by only looking for button transitions (e.g. last time the code ran the button was not pressed and this time it is pressed). It then toggles the state of beltStatus if this transition is detected. After that, the motor output is set by using another ternary operation to typecast the boolean belt state as a double.

Ether
29-05-2012, 14:06
beltStatus = beltStatus ? false : true;

or:

beltStatus = !beltStatus;

linuxboy
02-06-2012, 04:30
In terms of having things run only once per button press the command based template for WPILib has a nice feature where it takes care of that for you in your OI class.

Pseudo code for OI.java
Button toggle = new JoystickButton(BUTTON-NUMBER); //put a joystick button into a var
toggle.whenPressed(new toggleConveyorCommand); //upon press run the toggle command once

Pseudo code for toggleConveyorCommand.java:
execute() { //the execute part
if(Conveyor.getInstance().isRunning()) {//if the conveyor singleton is running
Conveyor.getInstance().stop(); //stop it
} else { //if not
Conveyor.getInstance().start();// start it
}
}

daniel_dsouza
08-06-2012, 16:04
You could do this in 2 parts:

//In the code that iterates:
if (getButton() == true) state = true; //if button is pressed, var goes to true
else if(state && !getButton()) { //if button was pressed, but isn't now
belt.toggle();
state= false; //says button was not pressed for next instance
}

//In your belt class:
public void toggle() {
if (motor.get() == 1) motor.set(0); //this could be simpler depending on your application
else if (motor.get == 0) motor.set(1);
}

This is similar to some sensitivity code we wrote last year:
if (GAMEPAD_R1) shiftUp = true;
else if(GAMEPAD_R2) shiftDown = true;
else if(shiftUp && !GAMEPAD_R1) { //only allows shift if button has been pushed, then released, to allow one shift per click.
drivetrain.shift(true);
shiftUp = false;
}
else if(shiftDown && !GAMEPAD_R2){
drivetrain.shift(false);
shiftDown = false;
}