What absolute encoders do you all use for swerve drive? Any tips for using them in code would be appreciated too!
Do you know what motors you’ll be using for the azimuth?
It really depends on the module. CANCoders and SRX Mag Encoders are the most popular for most modules, but the REV module uses the REV through bore encoder.
The usage in code is very similar between every encoder, module, and motor, just with different units. You’ll find the absolute encoders in the SwerveModule class in almost any swerve code, usually under a method called something like resetToAbsolute()
. Ideally, the only time you use the absolute encoder is to zero the steering motor’s integrated encoder once at startup. For this to work though, you need to make sure the steering gear ratio is exact in code.
For an example with CANCoders and Falcons, you can look at BaseFalconSwerve. For REV through bores and NEOs, you can look at REV’s example code (note that REV recommends to reset the encoder zero using REV hardware client, and not by a value in the code).
My main piece of advice would be to take extra care when finding the encoder offsets. Use a piece of metal, not wood (wood is usually too bendy). Make sure that the bevel gears are all on the same side, and make sure that driving in the positive direction, with an increasing encoder count, makes the robot go forward. Going through all of this means that you should only have to find the values one time, and never again.
If one or more modules do appear to be veering in their own direction, it could be an issue with the absolute encoders. (First insure that your steering gear ratio is correct in code). We had an issue where we didn’t properly glue our magnets in one of our MK4i’s, causing significant drift (5+ degrees) after each match, meaning we had to rezero that one module after every match.
We usually use Falcons, but since we’re trying to make a fully featured code library we want good compatibility with all swerve drives.
Why is it better to use the relative encoder for swerve drive most of the time rather than the absolute encoder?
It depends on latancy, many people chose ro seed there relative encoder measurements with ther absolute measurements, or their rotor encoder woth ther absolute encoder. This is generally done to avoid latency, but what you doo depends on rhe encoder. Besides, enocder choise is heavaly dependent on the motor controller you are using amd what works best with it.
Using the absolute encoder to zero the motor encoder can simplify the code quite a bit, since you can just zero once then use the motor controller’s onboard PID controller, rather than using a WPILib PID controller with an external feedback sensor.
Latency is another reason, but unless a team goes in really deep with swerve optimizations, it probably doesn’t matter.
We actually do have support for a number of different encoders built in (while leveraging native performance improvemrnts for certain motor/encoder combos that actually outperform YAGSL). I believe they were simply trying to understand the reasons behind why diffrent teams use diffrent encoders and wheich ones are used moat often. Swerve isn’t where they do most of their dev work in BreakerLib (the library they refrenced).
We used the Thrifty Bot Absolute Magnetic Encoders. Once we had the right encoder housings for our swerve modules, they worked great.
They produce an analog signal from 0 to the buss voltage depending on the angle. We just used the Analog Input Pins on the Rio.
I would love to know how you achieved this!
I have been contemplating placing portions of YAGSL into C++ and use JNI to get a performance increase however I am leaning against it because i want YAGSL to serve as a way for students to understand how swerve drive works.
If you are referring to CANCoders fusing or throughbore fusing with sparkmax’s I do not optimize for CANCoder fusing since CAN issues would be extremely dangerous during a match with them fused and I fall back to relative encoders if absolute encoder readings fail. I do fuse throughbore’s to SparkMax’s if theyre are setup (since there is less of a chance of a disconnect)
While we too are contemplating moving to JNI for a performance bump as we’ve basically maxed out our rio 2, I was indead referring to fusing. While there is the chance of a disconnect as it stands, we are in the process of leveraging BreakerLib’s Self Test functionality to detect encoder failures/faults (already in place, but being improved) and dynamically fall back to the motor’s encoder alone.
From experience I found that when using the unsoldered CANCoders (which we didn’t solder well the first few times) they appeared fine while practicing and during off the ground testing. The second the bot collided caused issues with the canbus which was traced to those CANCoders. In a ideal world teams would tug test, jiggle every connection, and perform collision tests I would not expect every team to do this. Self-tests would help with that but an automatic fall-back should be better incase of unexpected failures mid-match.
I implemented this in YAGSL from democat’s library, here. After someone let me know about it.
A nice pattern for code that’s compatible with various encoders / motors / IMUs / etc. is dependency injection, combined with interface classes. The basic idea is that one defines an interface for encoders, one for smart motors, etc. Then, you can write the swerve module and drive base classes using only these generic interfaces. The swerve module class might also be one where using an interface class makes sense.
Here’s a C++ interface class for smart motors: Scrappy/SmartMotor.h at master · Jagwires7443/Scrappy · GitHub. This has an implementation for Spark Max, which makes using these really painless. It was going to have one for Falcon 500, then all the stuff happened. It also makes use of C++ units in a way that works with Spark Max.
One major benefit of this kind of de/composition is that is fosters separation of concerns – code for a particular kind of encoder or motor does not show up in the swerve module or drive base modules. The other is that it makes it much easier/cleaner to manage multiple types of devices. It would be nice if WPILib included these interface classes…
This is in their roadmap, actually.
I’ve done the same thing in my team library and can testify that it reduces swerve code by a huge amount.
In our testing with soldered CANcoders, we experienced very fiew reliability issues overall, even during our impact and continuous vibration testing. And those that we did experience woud have taken down the entire bus anyway. However our experience with the overall reliability of CAN connections leaves me with little doubt that the issues you experienced are definitely possible or even probable.
as a maybe…
This recent post discusses some of the reasons why this is hard.
It sounds like you’re proposing a generic IO layer such that (for example) each subsystem includes multiple LoggedMotor objects instead of a single SubsystemIO object. There’s nothing stopping you from using that structure (AdvantageKit doesn’t have strict requirements for how the user manages IO interfaces), but we have preferred per-subsystem IO implementations for several reasons: Most hardware can’t be abstracted with a one-size-fits-all approach. That may have been true in the days of PWM…
It’s definitely possible, though. I imagine if WPILib began pushing a new smart motor controller interface, vendors would likely at least try to conform some of their configuration to support the new interface. Furthermore, there’s nothing stopping a user from simply calling configurations on the vendor library’s class itself, rather than a standardized config call for every MC. This is what I’ve begun to shift towards in my team library.
Cross posting here as it seems that this crowd may have the answers we are looking for
Thanks!
Adding another datapoint to team soldered CanCoders. We used them on our custom swerve and had success, but they failed a ton in shop testing, especially with the extremely small solder pads. We had two instances of failure in competition, and I would recommend getting the pre-soldered ones, if that is the direction you are taking.