Temporarily Assigning a Variable

Back at it again with another programming question. As always I apologize if this has been answered somewhere, but I could not find an answer.

So I am trying to use a small toggling type function to assign a bool variable to true after a button press, and then revert it back to false after a certain amount of time has passed.

Here is my current code:

  if(Controller1.ButtonL2.pressing() == 1){
      if(toggle2 == false){
          toggle2 = true;
          task::sleep(2000); //<---Problem Area
          toggle2 = false;   //<--/
      }
      task::sleep(200);
  }

Currently all it does is stop the robot for 2 seconds and refuses to change the variable.

There is probably something really obvious I’m missing, that’s why I wanted a dedicated programmer, but alas, that is not the case.

Ya I see your code, but what exactly is happening when you run it?

I edited the OP to include that

So is button l2 supposed to be the toggle button?

Yes L2 is acting as the toggle button

Apologize if I dont respond for a bit, I wont have wifi for a while.

I’m assuming this if block is in some kind of loop.

Here’s what happens:

  1. Button pressed condition passes
  2. toggle2 starts false, so second condition passes
  3. toggle2 set to true
  4. program delays for 2 seconds and does nothing
  5. toggle2 set to false (second condition complete)
  6. program delays for 200ms and does nothing (first condition complete)
  7. rest of the loop executes

What you’re describing makes it sound like you want it to do something like this instead:

  1. Button is pressed and toggle2 is false
  2. Set toggle2 to true
  3. make note of the time (condition complete)
  4. Otherwise, if it has been two seconds since toggle2 became true,
  5. Set toggle2 to false (condition complete)
  6. rest of the loop executes

If you want other things to happen while it waits for two seconds, you either need to record the time and check the current time against the recorded time or handle the delay in a separate thread (which is much more complicated). Otherwise, just telling the single thread you have to delay for 2 seconds will cause all execution to delay for two seconds.

1 Like

try this:
if(Controller1.ButtonL2.pressing() == 1){
        toggle2 = true;
}
while(toggle2 == true){
        //whatever action
        task::sleep(2000);
        toggle2 = false; }

@Hackapi That will produce the same behavior as he’s already seeing. Sleeping for two seconds will sleep for two solid seconds no matter how you dress it up. He needs a way to eliminate the sleep(2000) altogether.

2 Likes

Would using the timer work?

Reset the timer or record its value when the button is pressed as well are setting the boolean to true.

In your while(true) loop, just keep checking the boolean. If the boolean is true, check the timer to see if enough time has passed. If it has, change the boolean back to false.

Ok, so how would I go about setting up the timer?

Btw the 200ms sleep is what I have for all my toggles so that they are not triggered 30x times over by a single press (there is probably a better way, but that’s for a dedicated programmer to figure out), and the issue of stopping the whole robot has not come up, most likely because of the short wait time comparatively. So that is why I used another sleep function to wait during the loop

try this…

bool toggle2 = false, L2Button = true;

if(Controller1.ButtonL2.pressing() && L2Button)
{
    toggle2 = !toggle2;
    L2Button = false;
}
if(!Controller1.ButtonL2.pressing()) L2Button = true;

If I wanted to make it a two-step toggle I would, but I would much rather have it as one press to simplify driving, but if that is only to stop me from slapping sleep functions everywhere then thanks.

What you wrote was not a toggle so much as a triggered pulse. There was no way for pressing the button again to unset the toggle.

If you want a true toggle on rising edge (when the button goes from not-pressed to pressed) with timeout, you need to add a piece onto the timer that we’ve been telling you about. A simple 200ms wait isn’t going to cut it.

Rising edge detection requires you to keep track of the last state of the button, and only trigger your action when the state changes in the direction you want. To put it in a truth table:

last button | this button || take action
----------------------------------------
      F     |       F     ||      F
      F     |       T     ||      T
      T     |       F     ||      F
      T     |       T     ||      F

So you would check (!last && current) to take action. The action would be changing the state of your toggle and setting the timeout time:

toggle2 = !toggle2;
lastTime = functionForCurrentTime();

There’s one last wrinkle to making this work right, and that’s how we set the value of last. If we just set it to whatever the button currently is whenever, we could run into a race condition where the state of the button changes after we’ve checked for it but before we set the state of last, meaning it could jump straight from the FF row to the TT row, skipping the FT row that we care about. So we only set last to true if we handled FT, so we add that to the two lines above and add this to handle resetting last to false:

last = last && current;

Them’s all the pieces.

2 Likes

you could also do…

void toggle()
{
    toggle2 = !toggle2;
}

Controller1.ButtonL2.pressed(toggle);

or

Controller1.ButtonL2.released(toggle);

https://help.vexcodingstudio.com/#pro/namespacevex/classvex_1_1controller_1_1button/pressed

Edit: I read your question wrong.

How about this:

int counter = 0;
while(true) // main program loop
{
 if( Controller1.ButtonL2.pressing() == 1 )
 {
     counter = 100; // 20 msec delay * 100 => 2 sec
 }
 else if( counter > 0 )
 {
    counter--;
    if( counter == 0 ) 
    { 
        // do something as 2 sec interval expires
    }
 }
 bool bBoolean = (counter>0 ? true : false);
 ...
 task::sleep(20);
}

As long as button is pressed counter variable is kept at its max value. When button is released it starts counting down to zero.

5 Likes
void toggle()
{
    toggle2 = true;
    toggleStart = vex::timer.time(); //time in millisconds
}

int main()
{
    Controller1.ButtonL2.pressed(toggle);

    while(true)
    {
        if(vex::timer.time() - toggleStart > 2000) toggle2 = false;

        vex::task::sleep(10);
    }
}

Like this toggle2 stays true for 2 seconds after you press the button

By the way I don’t use vex coding studio so I am not sure if vex::timer.time() is correct.

2 Likes

Ill see if these work guys, thanks!

hey @John_TYler,
thanks for your answer. i was also looking for the same and your solution worked for me.
thanks , best regards!!

3 Likes