Are loops ok in FRC Programming

Hi All, When i joined my team, I was told using loops was bad. Their reasoning for it is because teleop runs the code ever 20 milliseconds and a loop can hold that time up. So i have a couple questions? Is it bad to use loops when programming the robot. If so why is it bad? Also how does the FMS interact with the code.

Code inside of the Periodic functions in the main robot class will automatically loop every 20ms. In general it is probably a good idea to avoid using while() loops especially ones that don’t exit but for() loops can be very useful in a robot program.

4 Likes

While it would be wrong to say that loops are bad in every situation in FRC Programming, they should definitely be avoided when possible. This is especially true for any kind of control loop or other structure where you cannot guarantee it will exit, or exit swiftly.

A case where a loop would be acceptable, is where you want to perform the same action to an array of similar items, like say a sensor. If you have three sensors, have put them in an array, and want to zero all of them out. it would be perfectly acceptable in my eyes to use a for loop over the indexes of the array and zero out each sensor, or collect the data from them, ect.

An unacceptable case is where you want to reach a specific state, that could for any reason never be reached, or take an extended period of time to reach, like a control loop. You shouldn’t create your own while loops to say while not at a certain angle,turn left in place, because if anything went wrong, like the sensor being messed up, or a drive motor being backwards, it may take a while, or never reach the angle and the robot would be stuck forever or a long time in that loop, unable to respond or do any other actions.

Such control loops should either be in their own threads, or integrated such that they utilize the system periodic loop and give everything else their fair time to run as well.

1 Like

Note that the RoboRIO has more than one core. If you start a thread, it can use the second core and then a loop can be useful. For example, maybe you want something to happen for vision in that other thread and it can loop checking if you are on target. Even better is a loop that yields/sleeps so other threads can run. (Not in your main control thread of course).

Another good use case for loops is during auton. (Assuming auton comes back.) There’s no need to be receptive to the controller then.

Also, do make sure you have an exit point. For example end the loop if you have been if more than a few seconds.

Said another way - the software architecture of the periodic methods in Timed or Iterative robot base classes is designed such that the periodic function must be run every 20ms to maintain proper control of the robot.

If the function itself takes too long, it will not be possible to call it every 20ms.

If you are to use a loop, you must be able to prove that it will never cause any particular iteration to take too long. This is easier to do with a for loop than a while loop.

Therefor, in almost all embedded code development, while loops are considered a no-no. Basically, if you can’t do what you’re trying to do in a normally constructed for loop, you probably shouldn’t be doing it in the first place.

True long-running tasks can be placed in a different thread, a programming construct which tells the operating system that pieces of code are allowed to execute in parallel. This can be effective, but brings additional challenges with thread synchronization.

To the FMS question - it can vary year to year. In general the FMS only controls your driver station, which in turn broadcasts control packets to the robot. It is up to your robot code to run fast enough to accept and respond to those control packets - one of the reasons for requiring that 20ms periodic update loop. FIRST does publish some details in the FMS Whitepaper.

2 Likes

Just to be clear, there are four different loops in Java: for loop (c style for loop), while loop, do while loop, and the for each loop. The for each loop is great because unless you hijack an Iterable, that loop is basically guaranteed to exit. Now, with for, while, and do-while loops, these are not guaranteed to exit.

I can agree with this. If you use a for loop to count to 10, it will exit. Doing the same thing in a while loop is less readable.

I don’t agree with this. There are plenty of places that you can use a while loop in without trouble. Such as an Iterator to append to a list while iterating through it. I’ll admit you won’t need to use the while loop very much in FRC applications (we didn’t use any in our code this year), but you can’t just say that using a while loop is straight up bad.

I agree with most of what with everyone is saying. Use for-each loops as much as possible, use for loops (c style) frequently and use while or do-while loops only when you need to.

My use of weasel words “almost”, “basically”, and “probably” was purposeful. :slight_smile:

I do agree with you - there are plenty of ways you can use a while loop without getting in trouble. My point is that there are also ways where you will get in trouble - often in subtle and not predictable ways.

To simply say “No while loops” is just an engineering tradeoff to make - the code is a bit harder to write, but it reduces the code review effort and potentially prevents some types of bugs.

More often than not, it’s driven by history: If your team has had an issue using while loops before, they’ll likely be banned in the future.

However, if you have another mechanism of guaranteeing a predictable iteration count for every while loop (perhaps just code inspection if your source is small enough), such a hard-and-fast rule is not needed.

My comments are heavily influenced by this line of thought: code inspection gets harder as code gets larger and more complex. Auditing for all instances of the word “while” is comparatively easier for an arbitrarily large codebase.

1 Like

The real goal in FRC programming and real-time-ish embedded systems in general is to pay some attention to the temporal requirements. Paying some attention to time makes programming embedded systems much more complex than enterprise applications.

So can you use loops? That is really a syntax question. If you use them properly, making sure they cannot consume too much time, sure you can use loops. They are not of the devil! But you should NEVER structure your code in such a way that there is any chance of missing communications from the FMS. I think if you miss 3 messages you get shut down by the FMS!

Some of the app wizards hide the fact that you are already in a loop. Many posters in this thread allude to that when they say do NOT take more than 20ms. This is because the FMS communicates with the robot at a roughly 50Hz rate.

Properly designed loops are not such a big problem. But there are some classic problems that cause non-determinism (your “loop” taking varying amounts of time). Avoid doing memory allocation or formatted output in your loops that demand deterministic performance. That is tricky
in Java, less so in C++ and straightforward in C. This is one of the reasons
I tend to shy away from Java in embedded systems. So do not create new objects in your loops. Avoid calling printf or using cout or the Java equivalents. Memory allocation and formatted outputs are classic temporal problems. Create all your objects BEFORE getting into your tight loops. Use the smart dashboard libs (which really send messages) instead of printing things to the console in your tight loops.

Good luck!

1 Like

//If you’re using a loop to do a
System.out.println(“ExplosivesLead2412 is awesome!”);
/*Then I think that is a very good use off loops.
Jokes aside, there are various uses for them. Like, when you have rollers for intake, you could use a while loop for the button to continually intake until the button is no longer pressed.
*/

This is not something you should do because it won’t allow the periodic functions to be run until the button is no longer pressed. This will also not work because the joystick won’t be able to update its button state.

Instead of

while(buttonIsPressed){
    intake()
}
stopIntake()

Do

if(buttonIsPressed){
    intake()
else {
    stopIntake()
}

You will have to run the code for that in a periodic function.

6 Likes

Definitely part of the question.

In addition, classical discrete-time control theory principles assume a constant sample rate. Keeping your loop times consistent is how you keep the math working right.

Same. FRC has this unique requirement of being able to teach students to code quickly, making Java a good choice from the learning perspective. However, we’ve had issues with tight timing on loops getting messed up by the garbage collector coming along and running, throwing off timings.

I’m old-school. C and C++ are where it’s at for production-quality real-time embedded system software development.

Indeed. This is exactly the case I would not use any sort of loop, because it would halt any other processing until the button is released. Unless of course this halting is inside some separate thread (as already mentioned). I would definitely state this explicitly if it was your assumption.

1 Like

Truth! WPIlib hides this from you by timing your PID loops etc for you plus leveraging the FPGA to help. But there are many teams closing servos etc in control loops and they need to be deterministic for the math to work out.

ExplosivesLead2412:

Like, when you have rollers for intake, you could use a while loop for the button to continually intake until the button is no longer pressed.

This is poor temporal design. Just record the button transition from ‘not pushed’ to ‘pushed’ and vice versa. There is no need for a loop in this case. Indeed it will kill you since by definition a button cannot be depressed and released by a human in less time than it takes the FMS to drop you.