Swerve Offset Issue with CANCoder

Hello,

This year we decided to use swerve, and we have implemented it in the offseason. We are using the MK4i modules from SDS, running on NEOs and with CANcoders on each of them. Throughout the fall, we’ve tested our modules a lot and it all seemed to work without a problem.

Now, with our robot fully built, we seem to be running into some angle issues when booting up. Occasionally, it seems like one of our modules does not get the right offset; 3 modules work correctly when driving, but one of them is not pointing the right direction, causing our robot to move weirdly. Restarting the robot code solves this issue. This doesn’t always happen on the same module, and sometimes we can restart the code 20 times in a row without having an issue; it all seems completely random.

If it helps, we are using the CANcoder value at startup to seed our spark max encoder. I’ve tried putting in a delay before reading its value, and that seems to have reduced the frequency of the issue, but it did not solve it.

As we compete in Week 1, I am starting to get a bit stressed about this, as I don’t want to just pray that we’re lucky enough for it not to happen in comp. Any help is greatly appreciated!

  1. Are you using Phoenix 5, or Phoenix 6? It would be helpful if you shared your code.
  2. If you’re using 6, have your tried using waitForUpdate when you get the initial encoder absolute position? See this post for more info
  1. We are using Phoenix 6. Here is the code I use to seed my encoders:

In Base::Periodic:
if (m_TimerEncoder.Get() >= DriveConstant::delayBeforeSeedEncoders) {
m_TimerEncoder.Stop();
m_TimerEncoder.Reset();
SeedSwerveEncoders();
}

The function SeedSwerveEncoders():
void Base::SeedSwerveEncoders() {
m_FrontRightModule.SeedSparkMaxEncoder();
m_FrontLeftModule.SeedSparkMaxEncoder();
m_RearLeftModule.SeedSparkMaxEncoder();
m_RearRightModule.SeedSparkMaxEncoder();
}

And finally in each module:
void ModuleSwerve::SeedSparkMaxEncoder() {
m_TurningSparkMaxEncoder.SetPosition(
units::radian_t{m_TurningCANcoder.GetAbsolutePosition().GetValue()}.value());
}

This is something I added a few days ago, since before I was doing it in the constructor but realized maybe I wasn’t giving the CANcoder enough time to boot. The delay is set to 2.5 seconds btw.

  1. No, I haven’t tried using that method, that’s something I could try. Wouldn’t it basically be the same thing as my delay though?

Also something to note is that I made myself a button on our joystick that passes through the SeedSwerveEncoders(), and when having the issue, pressing it doesn’t solve the problem.

Using waitForUpdate() and then checking for success would be similar to just delaying, but more robust. Adding the delay might not wait long enough. My recommendation would be to put a quick check in periodic, and keep trying to seed the encoder if it hasn’t been successful yet.

  1. Create a field at the class level and set it to false.
  2. On every iteration of periodic , if the value is still false, try to seed the motor with the encoder’s position.
  3. When posVal.getError().isOK() returns true, and your motor controller returns revError.value == REVLibError.kOk, set the value of field to true.

Can you provide a link to your code, I ran into a similar issue last year using team 364’s codebase

So would something like this work? (I’m in cpp so things don’t seem to have the exact same name)
void ModuleSwerve::Periodic() {
if (!hasEncoderBeenSeeded) {
auto absoluteEncoderPose = m_TurningCANcoder.GetPosition().WaitForUpdate(0.1_s);
if (absoluteEncoderPose.IsAllGood()) {
m_TurningSparkMaxEncoder.SetPosition(
units::radian_t{absoluteEncoderPose.GetValue()}
.value());
hasEncoderBeenSeeded = true;
}
}
}

Also a difference I noticed between the code I was using and the code used in the post mentioned above was that I was calling the GetAbsolutePosition() method, while CTRE calls the GetPosition() method. I thought I was doing the right thing as I want to have the absolute position of my CANcoder?

Some of our code is in Canadian French, so there might be some parts that you can’t understand. If you want me to send it anyways let me know

Just a note, you can’t do absoluteEncoderPose.IsAllGood(), as IsAllGood() is a static function on BaseStatusSignal that takes a list of StatusSignal instances.
For a single StatusSignal instance, you would want to do absoluteEncoderPose.GetStatus().IsOK(). Otherwise, yes that would work.

In Phoenix 6, CANcoder boots to absolute, so for swerve azimuth you can use either.

Oops my mistake :slightly_smiling_face: I’ll try this tomorrow and let you know how it goes, thanks a lot for your help you’re amazing :+1:

Alright, so I just tried this bit of code today on our robot, and still it only works about half the time. I’m not sure what to do…

Here is the link to my code: RobotCommandBase2024/src/main/cpp/subsystems/ModuleSwerve.cpp at development · ASTRO7605/RobotCommandBase2024 · GitHub

1 Like

Is it possible that I was mistaken thinking this was a seeding issue? Could it actually be a CAN bus issue? We are running 4 CANcoders, 3 Talon SRXs and 12 SparkMaxes, and our CAN utilization tends to run high-ish (75-85%)

So, after a lot of testing, we’ve isolated the problem to this: whenever we get the issue, in our driver station before enabling we get this error:

ERROR 4 [CAN SPARK] IDs 5: WPILib or External HAL Error: CAN: Message not found

The ID for this error seems to change from time to time. This is on top of another error that is more frequent but with which the code still works:

ERROR 5 [CAN SPARK] IDs 2, Unable to retrieve SPARK firmware version. Please verify the deviceID field matches the configured CAN ID of the controller, and that the controller is connected to the CAN Bus.

This error is always on the same CAN ID, and we discovered through testing that this is always on the turning motor of the first ModuleSwerve that we construct. Sorry if this is too much information, I’m just trying to figure out what’s wrong.

This topic was automatically closed 365 days after the last reply. New replies are no longer allowed.