Programming Debugging Doc

Hey Y’all! I wanted to make a post on identifying the most common problems us programmers have faced over the years and make a document for it. Whether it’s your offsets not applying correctly to PID strategies, anything and everything will be helpful. If y’all would list out your own / teams most common problems with the different solutions to said problems that would be great! In the end, ideally this document will be a quick access for everyone to use.

Thanks!

2 Likes

Most common that I see: getting the programmer to click the link in the error message, which explains how to interpret and debug the information in the stack trace.

Second most common problem I see: Not reading the docs at all.

Third most common problem I see: Guessing and checking in a problem space too large to support that strategy. Targeted, strategic debugging (make a hypothesis, design an experiment to test it, actually test it, draw a conclusion, repeat) is what’s required, but frequently skipped by newer developers.

11 Likes

Some very specific programming issues I see coming up every year:

  • Forgetting that Java trigonometric functions deal with radians, not degrees. (Use Rotation2d instead.)
  • Switching randomly between inches, feet, and metres all over the code. (Use metres everywhere and convert other constants immediately with a multiplier.)
  • Forgetting that integer division in Java will quietly round. (Add “.0” to your gear ratio constants.)
  • Forgetting to add requirements to controlling commands. (But don’t add them to commands that only read status from a subsystem.)
  • Adding long-running loops to command lifecycle methods. (The lifecycle builds the loop for you. This is how commands multitask.)
  • Implementing default commands in the subsystem periodic. (It’s fine for the subsystem periodic to send the motor commands, but the policy decision has to come from a command.)
9 Likes

A simple thing that I catch new programmers doing that leads to confusing debugging is simply negating something (or * -1) when an input/output isn’t going in the right direction and the code ends up with negations all over the place that contradict each other or that need to be duplicated in multiple places each time.

The correct approach is to set the inversion in the API of the device or write a wrapper that adds the inversion so that your inputs/outputs are in the intended direction. Seems obvious, but it’s something I’ve had to be strict about. The one place I allow it is on joystick controls and we’ve written a decorator class for ourselves to avoid even that case. My go-to phrase is ‘ensure positive power equals positive motion’.

5 Likes

Yes. This is another recurring issueI I see. The usual symptom is that they throw in negations until joystick control works fine, but then the autonomous routines drive in circles or backwards.

4 Likes

Using the new WPILib Units library helps tremendously with things being in different units.

2 Likes

I agree to some extent, but Units comes with a couple of footguns regarding memory allocation and mutability. (Rotation2d also comes with the memory allocation problem.) Hard to encourage its use when no APIs accept it (yet).

And the Java units API is getting a rewrite for 2025:

5 Likes

Of course, the OP wants a catalog of programming errors and solutions but your emphasis on learning how to think and approach problem-solving is the only way that lasts a lifetime and is of general use.

OP should review the how to ask questions and its links to other very good posts. If one makes the effort to ask a good question, one can often answer the question themselves and more efficiently than waiting for others to do the work.

I agree but this does have the appearance of contrary for a common problem where questioner starts by proclaiming - “I’ve check the ___ and ___ and there can’t possibly be anything wrong (so I give up and make you guess what’s wrong).”

What APIs are you referring to? Just about every WPILib method that uses measurements as parameters has an overloaded method that takes in Units objects from what I’ve seen.
And we pretty much exclusively use Units objects as parameters where appropriate in our team library.

I understand your POV, the objective of this document is more to help individuals start asking the questions and engage a conversation instead of concluding like you said, “I have no clue what else to do” but instead say “Have you checked this” or “this problem seems familiar, maybe we’ve encountered it before, let’s refer to our common debugging doc”. No one knows every problem and every solution to a problem. FRC is built on collaboration, this post is for people to share their perspectives and expand everybody’s knowledge. I hope you understand.

Edit: the post you’ve provided is actually very helpful for future use. Thank you for that!

Well, that’s interesting. Looking for examples, I see there is now a lot more support for units than there used to be. I still see some classes that do not support units. e.g. Pose3d (although Translation3d partially does), PIDController, Trajectory.State. Some classes, like SwerveModulePosition, support units for construction but not for output. Also, it doesn’t look like measures are Sendable which makes it hard to use them with a dashboard.

I came across ImmutableMeasure, which partially mitigates the mutability problem I referred to above, and which should probably be mentioned on The Java Units Library.

So I guess I’m wrong to say that “no APIs accept it”, but I still think that “only use metres and convert other units immediately” is a simpler solution that solves most of the problem with lower overhead. I’m still trying to persuade my students to stop unpacking and reconstructing Pose2d everywhere, so I’m hesitant to introduce units, but likewise I can’t seem to stop people from measuring distances in feet and inches.

Out of curiousity (to avoid this for myself) what does this look like?
Also thank you for the list it is very helpful.

1 Like

Any programming loops in any of the command methods is suspect but especially don’t use looping in the execute since that is itself one iteration of the looping provided by the command based scheduler. An example might be using a while loop to converge or maintain a mechanism velocity or position with a PID controller. That conflicts with the looping already provided in the command scheduler.

you’re saying one shouldn’t call pidcontroller.calculate() inside of a commands execute function?

You calculate one iteration of a command in execute and PID calculate is one such calculation that you may do. The execute method is wrapped in a loop by the command scheduler so what you must not do is put another loop around it within the execute method.
Okay:pidcontroller.calculate();
Not Okay:while(!atSetpoint()) pidcontroller.calculate();
And you can check for at the setpoint in isFinished(). That’s where you put your if statements.

1 Like

I got into the PID example a little too deeply. There is a best-practice posted for PID controller that uses a better structure than using a command class.

1 Like

@SLAB-Mr.Thomas has already answered this well, but in short I would be very suspicious of any use of while or for inside the initialize, execute, isFinished, or end method of a command or in the periodic method of a subsystem. There’s some related discussion in this thread.

1 Like