Macro Help

Hi everyone,

I need some help creating a macro code for my robot. I made some code, but some some reason it moves the arm sometimes and others it just doesn’t do anything.

Here is ther code:

bool armposition = true;
while (true){
    if(Controller1.ButtonY.pressing()){
      if(armposition == true){
        arm.spinToPosition(450,rotationUnits::deg,90,velocityUnits::pct, false);
        armposition = false;
      }
      else if (armposition == false){
        arm.spinToPosition(0,rotationUnits::deg,90,velocityUnits::pct, false);
        armposition = true;
      }
    }
    if(Controller1.ButtonRight.pressing()){
      if(armposition == true){
        arm.spinToPosition(550,rotationUnits::deg,90,velocityUnits::pct, false);
        armposition = false;
      }
      else if (armposition == false){
        arm.spinToPosition(0,rotationUnits::deg,90,velocityUnits::pct, false);
        armposition = true;
      }
    }
}

Thank you! If you have any questions, please let me know.

How fast are your fingers?

Walk me thru what happens when the code runs. First, the loop runs with no buttons pushed so nothing happens.

Now, hold button y, assuming armPosition is true. The arm motor is told to spin and not wait for the movement to finish. The armPosition is set to false.

What happens the next time thru this loop? Do you think the button is being pressed still? How much time elapses between loop iterations?

2 Likes

I am waiting for about 3 seconds before I try clikcing it again. I have tried waiting 0.5 seconds and 10 seconds and the problem is still occuring.

What is probably happening is that since you are using a button.pressing function, the loop runs many times while the button is being pressed, since the spinToPosition function is also set to continue before completion.

Let’s say that you run your code and press the y button. What ends up happening is that the arm receives instruction to spin to 450, and then sets armposition to false, like you want it. However, the code then moves on to the armposition == false portion of the code, and sends instruction to the motor to spin back to 0. The code then cycles through the loop, over and over again until the button is no longer being pressed.

The reason this sometimes works is that sometimes the last instruction the code is to spin to 450, and sometimes to 0.

There are a couple of ways you can solve this:
a) Remove the “false” from each spinToPosition function. This will make the motor finish its movements before moving on in the code. Assuming your press is short enough, this should work. However, any other part of the code will not work during this stage. This is a simple fix, but not one I would recommend unless all else fails.

b) Use a button.pressed function instead. You will have to define the functions in a different part of the code, and call the function on button press. This is the method I would recommend using. It should look something like this:

void buttonY(){  
   if(armposition == true){
       arm.spinToPosition(450,rotationUnits::deg,90,velocityUnits::pct, false);
       armposition = false;
   }
   else if (armposition == false){
       arm.spinToPosition(0,rotationUnits::deg,90,velocityUnits::pct, false);
       armposition = true;
   }
}

void buttonR(){
   if(armposition == true){
       arm.spinToPosition(550,rotationUnits::deg,90,velocityUnits::pct, false);
       armposition = false;
     }
     else if (armposition == false){
       arm.spinToPosition(0,rotationUnits::deg,90,velocityUnits::pct, false);
       armposition = true;
     }
}

bool armposition = true;
Controller1.ButtonY.pressed(buttonY());
Controller1.ButtonR.pressed(buttonR());

One more note: I would suggest that you create shorthand variables for each button, so that you don’t have to type out the whole thing every time. It’ll look something like this:

int BY = Controller1.ButtonY.pressing();
int BR = Controller1.ButtonR.pressing();

Then, in your code, you can simply use “BY” or “BR” instead. It’ll look something like:

if(BY){
    //code
}
if(BR){
    //code
}

While this doesn’t seem like much now, as you start making more complex macros using with multiple cases depending on sensor values or multiple button presses, it’ll come in handy.

Edit: Code error fixed

2 Likes

Correct diagnosis of the problem with the code.

The proposed solution is close, and the spirit is there, but please DO NOT register ‘.pressed’ events inside of a loop.

1 Like

Wouldn’t the .pressed function be inside of the user control loop? Wouldn’t having the .pressed event inside the user control loop allow it to be used multiple times over the course of driver control?

Yes, but your loop probably runs once every 20 milliseconds. It is unlikely that you would be able to tap the button and have it in the “pressing()” state for exactly one loop.

1 Like

Be precise - “pressed” and “pressing” mean and do two very different things. One returns a state, the other registers a function to handle an event. Do not register event handlers inside a loop.

2 Likes

Some quick further research indicates that you are correct and my post has been edited to correct this. Thank you for bringing this to my attention and teaching me something today. It’s interesting to note, however, that I have put .pressed functions within loops before, and they have worked fine then, if I’m remembering correctly.

2 Likes

Thanks for your help! I was able to get it working sucessfully. Also for anyone using this in the future, make sure to make your function names majorly differrent from preset variables or else you might get this error.
image