I tried writing a method to make the swerve wheels align in a certain direction when the swerve is initialized. I calculated the offset of the CANcoders and now three of the wheels align properly. The problem is that when I try to align the fourth (by setting it to inverted in the constants class) and run the code again, all of the swerve wheels change orientation and none of them align.
Somehow it seems that swerve motors are affecting other swerve motors?
I’m very confused and any help would be greatly appreciated.
reset method basically aligns all the wheels at the start of the match to the “forward direction”, which I defined as the 0 of the CANcoders by subtracting the offset. It is the method I was just talking about.
Can you explain how you calculated the offsets? I see you have the parameter named steerAngleOffsetRad, which implies that it’s in radians, but CANCoder offsets are configured in rotations. Make sure you have the units right, your variable name may just be misleading.
I think your intention with resetToAbsoluteAngle() was probably to read the position of the CANCoder and tell the motor it is currently at that position. Do you agree?
If so, you need to read the position from the CANCoder, calculate the corresponding motor position with the gear ratio (or configure the gear ratio with SensorToMechanismRatio) and then call setPosition(double). You’re currently trying to command the motor to a position, but this method should be telling the motor it’s position based on the CANCoder’s position.
I forgot to change the name of the steerangleoffset. It is not in radians. I didn’t calculate it, but lined up all the wheels in the forward direction, and set that as the CANcoder 0 by using the values read from the CANcoders and putting their negative into the Magnetic Encoder class.
The reset method takes the value, read by the CANcoder in rotations, and passes it in to the motor divided by the gear ratio to get by how much we want the motor to rotate, using the set
method.
From what I understand, the set method for motors gives the motors a rotation to rotate by, not a position to “go to”.
I was printing values to the Smart Dashboard just for debugging purposes. And some of my code is commented out also for the same reason.
What do you mean by telling a motor “its position?”
Also how does me changing one motor to inverted change the others?
Our swerve also uses TalonFX, though for many reasons we chose to stay with Phoenix 5, rather than new Phoenix 6.
We also use CANCoders for this.
The idea was - we use CANCoders ONLY to determine the absolute position of the wheel when the robot is turned ON. Then we reset the TalonFX built-in encoders to the values that they should have, considering raw-units-per-degree. For instance, if we have 150 ticks per degree, and CANCoder determined that the wheel is at +3 degrees past absolute X-axis direction, we would set internal TalonFX encoder to 450 (there is more math involved, since the CANCoder absolue 0 is not really the absolute X-axis direction, but that’s trivial).
After that basically the internal TalonFX encoders have 0 matching the absolute X-axis, so all wheel turns are done via hardware PID. Some of that math is here, and the rest is in the same class.
I would like to avoid using relative encoders unless there is a solid reason to do so.
Just asking though, if you have both the CANcoder and the internal encoder inside of the motor, couldn’t you fuse the sensors for a more accurate reading?
Yes, Phoenix 5 is marked for removal in 2025. But it still works in 2024.
If you’re annoyed by the VSCode crossing the deprecated statements, use
@SuppressWarnings({ “removal” })
annotation
Not sure what you mean by “fusing sensors”. We use absolute encoder to calibrate the relative one. Periodic recalibration technically can take place, however, the drift on those is minimal, and you can use hardware PID, which is MUCH more forgiving for somewhat suboptimal PID values (because it corrects every 1ms instead of every 20).
Because of the 1ms Hardware PID loop (which you cannot do if a motor and encoder are not directly connected - meaning CANCoder cannot do that), ANY wheel turns in our case take less than 0.1s time, which makes the actual swerve drive VERY smoothly, and handle sudden trajectory changes well.
I think other posters explained this, but the CANCoder is an absolute encoder, that can read the position of the wheel, even between power cycles.
The encoder built in to the motor, on the other hand, is a relative encoder. It starts at zero every time you power cycle it. Besides, it’s geared down, so one rotation of the wheel takes more than one rotation of the motor.
Many teams (including mine) want to take advantage of the Talon FX smart motor controller to control the steering. An easy way to do this is to read the absolute position at startup from the CANCoder, and then seed that position to the motor, and then use the motor’s encoder from then on.
As I said above,
Yes, you can do this, but it’s a Phoenix Pro feature and requires a license.
This is incorrect. Using PositionVoltage commands the motor to go to a specific position, in rotations.
Finally, if you are using CANCoders, Talon FX motor controllers (Falcon 500 or Kraken), and a Pigeon 2 IMU, I highly recommend you use CTRE’s swerve project generator instead of starting from scratch.
So how does the odometry work? Isn’t it based on the position being the amount of rotations moved by the wheel to calculate the displacement in short intervals?
The motor has a relative encoder, but you can set it’s position by calling setPosition(double).
For example, let’s say you start up your robot and the wheel is pointed 90° to the left:
You read the wheel’s absolute position from the CANCoder by calling getAbsolutePosition() and it returns 0.25 rotations.
Assuming you did not configure the SensorToMechanismRatio, you convert 0.25 rotations to the number of motor rotations. You didn’t say what swerve module you have, so let’s assume it’s an SDS Mk4i with a ratio of 150/7:1. Your calculation will be 0.25 CANCoder rotations * (150/7) gear ratio = 5.357 motor rotations. var motorPosition = cancoderRotations * gearRatio;
You “seed” your motor’s relative encoder by calling setPosition with 5.357 setPosition(motorPosition)
Now that you’ve seeded your motor’s starting point, everything is relative from here. If you spin the motor, you can apply the gear ratio in reverse to calculate the wheel’s absolute position.
BTW, I recommend setting SensorToMechanismRatio in the motor’s configuration so you don’t have to deal with the gear ratio conversion in your code.
You are mostly correct. Odometry is based on the position of the drive wheels, but in meters, not in rotations.
You kind of changed lanes here. We’ve been talking about the azimuth (steering) of the swerve modules and I think you’re asking about the drive distance.
For odometry, you will need to provide SwerveModulePosition objects. You’ll have to provide the drive distance in meters and the azimuth angle as a Rotation2d.
Thank you so much for your help! I was really confused with Phoenix 6
Last question: for phoenix 6, the CANcoder has a setting to set it to Clockwise vs Counterclockwise (which I’m assuming is similar to inverting a motor). How do I know what to set it to? Last time I set it to the same direction the motor is set to, but I’m not sure that’s correct.