Function/Command Programming

So, my team is working on programming our skills autonomous and currently are almost finished. The only problem we are having now is running a function at the same time as another command. For example:

This is our function:

void FlapperHalf() 
    {
        Flapper.startRotateFor(200,rotationUnits::deg,100,velocityUnits::pct);
        while(Potentiometer2.value(analogUnits::range12bit) < 10)
        {
            Flapper.spin(vex::directionType::fwd, 0,vex::velocityUnits::pct);
            sleepMs(50);
        }
}

And we want to run it at the same time as another command. Example:

        RightWheel.startRotateFor(120,rotationUnits::deg,30,velocityUnits::pct);
        RightWheel2.startRotateFor(120,rotationUnits::deg,30,velocityUnits::pct);
        LeftWheel2.startRotateFor(120,rotationUnits::deg,30,velocityUnits::pct);
        LeftWheel.rotateFor(120,rotationUnits::deg,30,velocityUnits::pct);

How would I implement my function in my programming with the wheel rotations in order to have them run at the same time? We mainly want to do this so that we can have the robot back up while lifting the cap flipper during skills autonomous.

Oh, and I forgot to mention that we are using C++ Programming on Robot Mesh Studio for V5.

First I’ll note that I don’t program in C++. But also:

Right now you have a rotateFor at the end (I assume so that the function continues until all 4 are done.)
You can change the last rotateFor to a startRotateFor, and run your cap stuff while the drive is running.
After your cap stuff, put a “wait until LeftWheel is done” That way your drive doesn’t stop until the motors are at their position. Your final code will look kinda like:

RightWheel.startRotateFor(120,rotationUnits::deg,30,velocityUnits::pct);
RightWheel2.startRotateFor(120,rotationUnits::deg,30,velocityUnits::pct);
LeftWheel2.startRotateFor(120,rotationUnits::deg,30,velocityUnits::pct);
LeftWheel.startRotateFor(120,rotationUnits::deg,30,velocityUnits::pct);
Flapper.startRotateFor(200,rotationUnits::deg,100,velocityUnits::pct);
while(Potentiometer2.value(analogUnits::range12bit) < 10)
{
Flapper.spin(vex::directionType::fwd, 0,vex::velocityUnits::pct);
sleepMs(50);
}
while not (LeftWheel is done){
}

Obviously that’s not the right syntax, but I hope you see what I’m getting at. Good luck! :smile:

Did you mean to put them all as startRotatefor or does it need to be just the last one? In addition, is the syntax your referring to that isn’t probably right the “whileNot”?

Did you mean to put them all as startRotatefor or does it need to be just the last one?

No, I meant for them all to be startRotateFor, that’s important. Otherwise your motors all go one at a time.

In addition, is the syntax your referring to that isn’t probably right the “whileNot”?

Yes, and maybe some other things too, I’m not really sure. As long as you can understand it, though, you can code it.

I’m sure I’ll be able to decipher the correct syntax. Thanks for the help!

Just a note, trying to use startRotateFor then immediately calling spin will override the startRotateFor. If you want to do movement based on sensors that aren’t in the motors, ignore the various forms of rotateFor and rotateTo.

For autonomous where there is usually no loop like driver control has, one way to accomplish tasks that would otherwise be blocking is to separate them into their own threads. There are some complexities to using threads, especially in the context of the competition template, but they can definitely be done.

I wrote some documents a while back on threading and the competition template, just talking about the basics of what the classes and methods do and are for.

The first step to using a thread for a task in autonomous is writing a function to execute the task, which you have already done. The next is to start a thread that uses that function when you want it to execute:

thread doFlapperHalf(FlapperHalf);

This will start a thread that runs your function. The program will switch back and forth between active threads while it has more than one. (In a competition scenario, this will be between the competition management thread, the autonomous or driver control thread, any threads you have started, and the main thread if it is still running.)

The complication to using your own threads with the competition template is that the competition manager will only automatically stop the autonomous or drivercontrol threads. Any threads that you create will have to be stopped by you. For your example, it’s fairly easy to accomplish this by adding some extra checks to your while loop:

while (Potentiometer2.value(analogUnits::range12bit) < 10
    && Competition.isAutonomous()
    && Competition.isEnabled()) {

If the competition mode changes to disabled or driver control, the while loop will exit and the thread will end. If you later want to wait to make sure that the task is finished, you can do so by using the join method on the thread:

doFlapperHalf.join();

Join will block until the thread in question is finished. So with your example with driving forward, if you wanted both tasks to be complete before moving on you could do:

thread doFlapperHalf(FlapperHalf);
RightWheel.startRotateFor(120,rotationUnits::deg,30,velocityUnits::pct);
RightWheel2.startRotateFor(120,rotationUnits::deg,30,velocityUnits::pct);
LeftWheel2.startRotateFor(120,rotationUnits::deg,30,velocityUnits::pct);
LeftWheel.RotateFor(120,rotationUnits::deg,30,velocityUnits::pct);
doFlapperHalf.join();

One limitation of threads, however, is that you can’t pass arguments to the functions that they call. This means that they are most useful for actions that will always be the same, or for monitoring and responding to a sensor independent from the rest of the program.

So, the last code example you gave us is necessary, but do I have to do the top two sets of code? Because this is only for my skills autonomous where I won’t be using driver control. And will the wheels be moving as the motor for the cap flipper is moving to the potentiometer value? Because that was my original goal.

Is there any way to do this without a potentiometer. For example, can I do it within the motors like this?

Flapper.startRotateTo(200,rotationUnits::deg,40,velocityUnits::pct);
        RightWheel.startRotateFor(-220,rotationUnits::deg,40,velocityUnits::pct);
        RightWheel2.startRotateFor(-220,rotationUnits::deg,40,velocityUnits::pct);
        LeftWheel2.startRotateFor(-220,rotationUnits::deg,40,velocityUnits::pct);
        LeftWheel.rotateFor(-220,rotationUnits::deg,40,velocityUnits::pct);

Do I have to declare the zero point, or does it automatically zero out where I start it at the beginning of the autonomous?

If you let the motor’s encoder handle things, that is done in the motor hardware itself, so you would not have to start up a thread in code to handle watching a separate sensor.

As for where the motors’ zero point is, it’s where the motors are when the program starts, or wherever they are when you call their resetRotation method. (There is also a setRotation method that sets the current position as some arbitrary position, meaning zero would be offset from the current position by whatever the current position was told to think it was.) The rotateFor and startRotateFor methods don’t care where the zero position is, though.

If you use the motor’s encoder to handle things, I would change the logic of how you wait for all the motors to settle a bit. Rather than calling startRotateTo/For on all but the last motor, you would call startRotateTo/For on every motor and wait for all of them to report isDone or none of them to report isSpinning:

Flapper.startRotateTo (etc);
Wheel1.startRotateFor (etc);
//etc
Wheel4.startRotateFor (etc);
while (Flapper.isSpinning()
    //for each motor
    || Wheel4.isSpinning()) {
        //do nothing
}

It worked. Thanks for the help!