How to Code Macros (PROS)

How do you code a macro in PROS? I’m not looking for anything too crazy, even an old program (preferably in PROS) that I could study would work.

1 Like

It’s standard C, same as VEXcode, RobotMesh C++ etc.
some examples here.
http://www.cs.yale.edu/homes/aspnes/pinewiki/C(2f)Macros.html

2 Likes

It seems to me like he’s not looking for preprocessor macro, only for button “macro” where you press a button and robot does an action.
To that end–you’re going to need to use tasks and probably global booleans to enable/disable an action. It’s a complex question because a lot of people do macros different ways, such as with state machines.

2 Likes

@Zenix You said that you wanted to learn about PROS macros at our last team meeting. Maybe check out these resources.

2 Likes

Steps

The way I like to program macros is without any tasks and use a step variable. I define a global variable like liftMacroStep. Then is the main loop I have…

if(liftMacroStep == 0)
{
    if(button press) liftMacroStep++;
}
else if(liftMacroStep == 1)
{
    //Do stuff
    if(condition reached) liftMacroStep++;
}
else if(liftMacroStep == 2)
{
    //Do more stuff
    if(condition reached) liftMacroStep++;
}
else if...

With this it waits at step 0 and than when a button is pressed it runs the other steps. Also remember to set liftMacroStep back to 0 at the last step. Using this method you cannot have any time delays because it would stop the whole loop, but you can still have a timed step. You create a variable, liftTimerStart, and set it to pros::millis(), the current time, at the end of the previous step and then you can check if some amount of time has elapsed: pros::millis() - liftTimerStart > timeInMilliseconds. This type of macro can be canceled by setting liftMacroStep back to 0.

With this you can achieve some more complex results, like for example in turning point I needed to calibrate a system before it can be used. The first few steps did that (as soon as the program started) and then when it reached step 3 it would run the normal controls. Also if the calibration failed we could rerun it by setting the step to 0. If you wan to see my turning point program that uses this method here is the github.


Tasks

Another way, which probably is simpler is to use tasks.

All the macro code goes into a function: this is like set motor speed to this, and wait until this, and sleep for this long. Here is it fine to put timeouts because it wouldn’t stop anything else from running. Then when you want to running the macro you do this…

pros::task_t liftMacroTask;

void liftMacro(void * param)
{
    //macro code
}

void opcontrol()
{
    while(true)
    {
        if(button press && liftMacroTask.get_state() != E_TASK_STATE_RUNNING)
            liftMacroTask = pros::c::task_create(liftMacro, (void*)"PROS",
            TASK_PRIORITY_DEFAULT, TASK_STACK_DEPTH_DEFAULT, "LiftMacroTask");
        if(other button press && liftMacroTask.get_state() != TASK_STATE_DELETED) 
            liftMacroTask.remove();

        //rest of you code

        pros::delay(3);
    }
}

This simply starts the task when the macro button is pressed. When the task is done liftMacroTask.get_state() wouldn’t say running anymore and the task can started again. The other if statement is to cancel the macro and stops the task.

4 Likes

From what I know, isn’t Pros based off of standard C++?

1 Like

What’s the difference between, macros and standard pros? Does it make a difference to how the robot moves?

1 Like

Not sure when you mean, but there are two types of macros. C++ and therefore PROS have macros which are like #define macroName(x) (x + x) which are bits of code that the compiler puts in before compiling the program. So…

#define gg +5

12 gg;

will get replaced with…

12 + 5;

and then compiled.
http://cpp.sh/6kyud

Then there are macros which are when a button is pressed, it will run a sequence of action like for example spin up a flywheel to a certain speed, then when it reaches that speed it will launch one ball and set the flywheel to a lower speed. Basically instead of you needing to do all those actions you click a button and it does it for, usually fast.

1 Like

Sorry for not being clear in the original post, I am curious about button macros, being able to execute a series of actions with one input

That first way of doing button macros is very similar to a statemachine. However, some syntactic improvements can be made.
It is a good idea to enumerate your states using enum or enum class and it is better to use a switch statement instead of an if/elseif/else tree.
Here is an example:

enum class liftStates {
  off,
  up,
  waitForPress
};

liftStates liftState = liftStates::off;

while(true) {
  switch(liftState) {
    case liftStates::off:
    lift.move(0);
    break;

    case liftStates::up:
    lift.move(127);
    break;

    case liftStates::waitForPress:
    if(button press) liftState = liftStates::up;
    break;
  }
  pros::delay(20);
}

You can see this leads to a cleaner and more concise code.

In my code last year, I ended up using a massive statemachine for my flywheel angler, that used a queue to load up a series of commands that would execute in a sequence, and insert new states if needed.

  enum shootStates {
    off, //control to flywheel and intake
    standby, //back position, control to flywheel
    angling, //indefinite angling
    cycle, //head to back position
    extend, //move to extended position
    waitForSlip, //wait until hood slips
    waitForRetract, //wait until hood back to 0 pos
    angleTop, //drop hood to top angle
    angleMiddle, //drop hood to middle angle
    angleTopPlatform, //angle top from platform
    angleMiddlePlatform, //angle middle from platform
    angleOut, //drop hood to out (ground flag) angle
    angleTarget, //drop hood to target angle
    waitForDoubleShot, //if distance is large enough, wait before second shot
    waitForBall, //wait for ball to be in indexer
    waitForFlywheel, //wait until flywheel is ready
    enableShoot, //shoot indexer
    waitForShoot, //delay
    reportDone, //lets autonomous know sequence is done
    loopJob, //reloads current job
    loopMacro //reloads current macro
  };

I could then construct named macros with sequences of those actions, and have the macros trigger on button presses. For example, the doubleshot macro was done using this sequence: angleTop, enableShoot, angleMiddle, waitForDoubleShot, enableShoot, reportDone and the cycling would be automatically inserted in that sequence when needed.

I recommend everyone reads about statemachines, as they can be simply implemented (switch statements) and are very powerful.

5 Likes