Similar to last year, the WPILib team is seeking feedback on the many improvements and changes made to WPILib in 2023. This can be about the library itself, tools, or documentation.
I like to structure this kind of feedback ask as looking for the good, the bad, and the ugly:
The good: What worked well? What did you find particularly beneficial to your team? What would you like to see more of?
The bad: What didn’t work? What did you struggle with? What would you like to see changed?
The ugly: What did you have to hack around to make it work for you? What made figuring out the right solution more difficult for you (e.g. wasted precious time)?
We’re currently working on our plans/priorities for next year. Suggestions are certainly welcome, but I’ll note that since WPILib is a volunteer effort / community project, the best way to see a feature get implemented is to implement it yourself, or get someone in the community interested in implementing it. We welcome both ideas and contributors!
More exotic drivetrains, programming subteams almost never get a choice in design and when dealing with anything outside of Swerve, Mecanum, or Differential there is no support for built in drive classes for motor safety for less experienced teams, and there is absolutely zero support for pose estimators and simulation frameworks. It would be nice to see x drive, butterfly drive, and more get wider support it’s unfortunate to see software be the limit for teams trying new solutions.
also like if anyone could help translating H-Drive support to cpp would be fantastic
The good: What worked well? What did you find particularly beneficial to your team? What would you like to see more of?
WPILib is solid. I especially like the new trigger bindings introduced this season. The level of tech support is great (always very responsive and masterful).
The bad: What didn’t work? What did you struggle with? What would you like to see changed?
The documentation always trails the implementation a bit.
The ugly: What did you have to hack around to make it work for you? What made figuring out the right solution more difficult for you (e.g. wasted precious time)?
The Good: Documentation is excellent and a fantastic resource. Something we refer to constantly.
The Bad: Shuffleboard. I want to love it so much, but it just has so many warts. There were many times we had to restart it because the UI elements wouldn’t show current data and other issues. It is a bit of a resource hog and still gets hung up at times. I suppose I should give it credit as a really strong tool as we still continue to use it even with all of these issues.
The Ugly: Holonomic trajectory generation and following. The HolonomicDriveController is awesome. We were able to switch from a fused heading RamseteController implementation to one using HolonomicDriveController without much trouble, but we weren’t able to use the holonomic facing information that our trajectory generation tool, PathPlanner, produced…so we had to hack around a bit to get some heading change we wanted in our trajectories to work.
Good: The command-based framework once again proved to be a blessing. Thanks to the command-based framework and its incredible extensibility, we created extensible, efficient autonomous routines with as little code as possible. Our auton structure evolved a lot and eventually converged into extremely simple commands strung together to form complex autons, all thanks to command-based!
The new CommandXboxController class is awesome, by the way. Made it so we didn’t need any super hacky solutions for the d-pad or triggers.
CommandXboxController is great and makes doing bindings for commands much easier, especially in conjunction with using lambdas to avoid creating a bunch of redundant commands.
There were some things about how Command Groups handled subsystem requirements that were a tad unintuitive at first, but nothing that couldn’t be worked with. Maybe I’m missing something, but it would be nice to have those rules spelled out more explicitly in the docs. All in all, the Command based framework was very helpful for our programming and something I would recommend.
Like many others, we did experience some problems with Shuffleboard, typically stemming from having it be open too long. Restarting the tool normally fixed those, though. In the future, I would like there to be a very easy way to schedule commands from Shuffleboard - the example of simply putting the Command on SmartDashboard failed (although admittedly I was coding under high time pressure in less than ideal conditions [lunch during DCMP] and have not returned to the original idea) but it would be a very nice thing to have in the future (e.g. one could be tuning parts of autonomous routines multiple times in a practice match or bind very specialized commands to the dashboard to avoid accidentally triggering them).
Good: SE(3) and SO(3) support in a easily useable way, NT4 works super well
The bad: Shuffleboard comments from above, no super simple way to do sysid for swerve (had to do some workarounds),
The ugly: Driverstation returns red if not connected instead of the invalid enum that exists (almost messed us up if I hadn’t seen a message on frc discord about it)
I would love mutable versions of the translation classes so we’re not required to create dozens of objects when doing transformations on them.
ugly:
Pose3d’s exp and log functions are really slow. (~17% of the time of our robot loop was spent in these functions.) This probably stems from the dozens of allocations (I counted 23) that this method calls and the number of times that we call them
It wasn’t clear to me that kinematics classes aren’t thread safe (e.g. SwerveDriveKinematics) & the corresponding crashes were annoying to debug.
But before we do that, we should refactor the odometry and pose estimator classes. In 2020, we added separate classes for each drivetrain because there weren’t that many combinations, but it’ll become unmaintainable if we add more.
We currently have to modify six nearly identical classes any time we need to fix a bug in or add a feature to pose estimation (3 drivetrain types x 2 languages). Each new drivetrain type adds two new kinematics classes, two new odometry classes, and two new pose estimator classes.
Interesting. We may have to call the C++ version via JNI, since we don’t have much control over what EJML does internally for allocations, and making a bunch of geometry member variables to reuse for the calculation would bloat the size of what’s supposed to be a cheap-to-copy type.
None of our classes are thread-safe. The user is expected to implement thread safety themselves since the common case of cooperative multitasking doesn’t need it, and it introduces overhead.
I don’t know if this was ever figured out, but experiencing the problems in this thread (std:bad_alloc crashes) this year was very frustrating. Don’t know exactly what is causing the crash or if it’s even because of WPILib.
I could try working on abstracting the pose estimators out but I don’t think it’s going to be easy as they each use different interpolation records, handle rotation differently, and much more, I don’t see an easy way to make even differential and H-drive one system let alone swerve too, but I can look into it.
I was the main software mentor for a rookie team (9044, source code), so some of my criticisms may be due to blind spots rather than actual WPIlib deficiencies.
The good: Command-based robot control worked quite well, once we figured out how to put the pieces together.
The bad: The asynchronous nature of many APIs was obscured, whether by lack of documentation or overloaded methods omitting the timeout parameter. We didn’t understand this aspect of robot programming for many months. To be fair, it never bit us with WPIlib (but oh boy did an async initialization gotcha in the navX API bite us).
The ugly: The number of footguns related to unit conversions is epic. It should not be easy to, for example, combine APIs which deal in encoder ticks per 100ms versus meters per second. One might argue that this provides good exercise for students, but IMO it instead teaches dangerous API design. Critically, angle measurement is variously in degrees (clockwise/counterclockwise) or radians, and 0 is variously in the direction of the positive x axis or the positive y axis. In some cases degrees vs radians is abstracted, but this inconsistency helps obscure whether there’s even a consistent direction of positive rotation. These coordinate/angle ambiguities added many hours to our initial swerve drive bring-up.
Regarding coordinate/rotation transformations, we may have overlooked something, but we never found a way to mirror axes, and we had to go to a lot of trouble developing workarounds that didn’t compose with WPIlib APIs.
Finally, we went way down the path of using TrajectoryGenerator before appreciating how brittle it is in the context of swerve drive; working around the problems was a lot of trouble, and the results were never more than passable. I think most teams use PathPlanner, but we didn’t know that and fell into what felt like a trap in retrospect.
I’m not sure this fits into any of the above categories: I looked for introspection tools for understanding what was going on in the scheduler, or collecting performance profiles, and never found anything particularly useful, whether live or recorded. A lot of these frustrations felt like typical remote debugging with an incomplete developer toolchain, but attempts at workarounds, such as using NetworkTables, quickly added enough overhead to cause loop overruns, so we did a lot of black-box debugging by necessity. Maybe there’s some existing documentation that could help; if not I’d love to see some improvements here in documentation and/or tooling.
We think it’s mostly because of Java 17 and the current GC settings. These almost certainly need some tuning/testing as @varun123’s post discusses. We may end up needing to have different GC settings for Rio1 and Rio2 due to memory and processor speed differences. We also need to do a bit more tuning of some of the native memory allocations–we have memory pools (to reduce allocation churn) in a few areas that result in “holding onto” memory after the peak demand has passed, these need some tuning as well to release memory back to the system after some period of time.
This was an intentional design decision. You’re right that it increases GC pressure, but immutable objects are much easier to reason about and avoid footguns.
It’s worth noting that data logs are lower overhead than NT (NT has to do more work). Several teams I talked to added their own switching between data logs and NT, we want to make this easier to do in a more unified fashion (or better yet, just speed up NT for the common case).
I agree. At least Phoenix Pro moved to SI units. WPILib is already pretty loud with unit suffixes in Java, so there’s not much more we can do until Java gets value types that don’t incur a bunch of GC overhead. C++'s units system solves this problem in a zero-overhead way.
The CoordinateSystem class only handles transformations between coordinate systems with the same handedness (right or left) because they are pure rotations. Mirroring an axis switches handedness and can’t be represented with 3D rotations alone.
We’ve considered adding support for converting between left-handed and right-handed coordinate systems, but I don’t think that would help you since I assume what you’re doing is mirroring an axis and still treating it as North-West-Up convention to deal with the field assymetry.
WPILib’s TrajectoryGenerator and PathWeaver UI were written in 2020 for differential drives only, before swerve became a huge thing. Assuming we don’t replace it, we should document that better. We’re considering replacements like:
This will eventually support swerve and diff drive. Since it’s based on React, we need to interface with a native CasADi backend or a Wasm Sleipnir backend. The latter backend is much faster, but is much less stable.
The good:
I love the C++ units library. Since I adapted it I haven’t had any issues with units getting mixed up.
The built-in debugger is also amazing. It made it really easy to fix segfaults that would otherwise take hours.
The bad:
Personally, I don’t like Gradle as a C++ build tool. It breaks more often than it should, the user experience isn’t great and support is very minimal. I’ve never seen Gradle used outside of FIRST for C++ and installing libraries for it is a pain.
Shuffleboard, shuffleboard, glass still leave a lot to be desired. A lot of quirks and bugs with each.
We used advantage kit for data logging and telemetry and it was awesome, It would be sweet if something similar was built in that would just log anything that was put into network tables and then a corresponding tool for visualizing the logs / telemetry.
This is my first time using Java in some time. Memory use is certainly concerning on rio1, we only had two or three megabytes of free RAM available for the majority of the season. Just before Houston, we got OOM during some practice matches twice in a row. This was spooky enough that we went through the effort of disabling the web server to free up 50 MB of RAM.
Tangently related to the above, and not really related to WPILIB, the SD card spooks me on the Rio 2… I want the additional processing power and RAM but I have heard too many horror stories about SD failures
We use Helix navigator for path generation, it would be neat to see something like this integrated out of the box.
Overall I’m very happy with WPILIB tho, keep up the great work!!!