Swerve MK4I wheels angle

We (Team#9487), are trying to configure our MK4I swerve wheels, however, when we try to make the wheels go in a straight line, they all move in random directions. We tried inverting the motors in the programming and even correcting the PID, but the PID only served to reduce the noise of the friction between the gears (For those interested, we program in Java). Of the four modules, one is without the cancoder, but the motors are all connected to the sparkmax, so it should work regardless, right? And in any case, if the cancoder is a problem, at least the wheels with the cancoder should work in theory. We welcome all kinds of help.

Nós (Equipe#9487), estamos tentando configurar nossas rodas swerve MK4I, contudo, quando tentamos fazer as rodas andarem em linha reta, todas elas fazem o movimento de translação em direções aleatórias. Tentamos inverter os motores na programação e até mesmo corrigir o PID, contudo o PID só serviu para diminuir o barulho dos atritos entre as engrenagens (Para os interessados, nós programamos em Java). Dos quatro módulos, um está sem o cancoder, contudo os motores estão todos ligados aos sparkmax, ou seja, deveria funcionar independente disso, certo? E de qualquer modo, caso o cancoder possa prejudicar, pelo menos as rodas com cancoder deveriam funcionar em tese. Aceitamos todos os tipos de ajuda.

Two things I can think of, without seeing your code.

Are you setting an offset for each encoder? If you don’t know what I mean I’d be happy to explain, but if you do I won’t bother, just let me know.

Are the magnets glued into the shafts under the encoders? We missed that during assembly, so the magnets where free to spin around in there, which changed the wheel angle. This caused it to sem like the encoders were drifting. We’d set the offsets, carefully move forward ok, then start moving around and the wheels would get further and further off.

Oh and you will need that forth CANCoder, the NEO built in encoder will tell you how far the motor has turned, but the CANCoder is an absolute encoder, that will tell you the direction the wheel is actually facing.

But you’re right, you should be able to get the other three wheels turning correctly at least.

A bit more context would be helpful:

Are you using the absolute encoder for the steering control loop? Or just to initialize the starting position and then using the motor encoder for steering control after that?

If you start with the wheels pointed in the direction you intend to go, and you only try to move the robot in that direction, do they stay in alignment, or do they turn to random angles?

If the wheels stay in alignment when you initially try to drive in the direction that the wheels were initially set to, do they then start to move in random directions as you try to change direction?

Can you display the module angle on the dashboard and watch it as you try to drive? Does the displayed angle match the command as you try to drive at 0, 90, 180 and 270 degree directions?

You can set the robot up on blocks for these tests and then watch all the modules do their thing.

I don’t think so, but I’d like you to explain what you mean, just to be sure

Respectfully: yes, we’re using it for the transmission system:
They’re spinning in random directions. We even tried presetting it, but all it took was one movement for the wheels to misalign;
Yes, when we try to change the direction of the wheels, they go in random directions;
No, we couldn’t visualize it.
That’s right

If they are turning to random directions as soon as you start to move, then it does not sound like they are properly initializing.

In order to test and see if this is your only issue, you can comment out the initialization of the module angles and add a line of code that sets the initial angle to zero. Then you can manually (by hand) turn all the modules to face forward before powering on the robot. You can then try moving the robot translation controls in different directions and see if all the wheels rotate to the same angle.

With one of the Cancoders not installed, that module will more than likely start spinning in random directions. But the other 3 might work fine. If they don’t, then you have some other issues to work on.

Once the module angles are initialized, you can use the motor encoder for steering control instead of the absolute encoders. You should be able to read the motor encoder count (it will initialize to zero at power up). Assuming that you know the encoder count per motor revolution and you know the gear ratio between the motor rotation and the module rotation, you should be able to take the motor encoder count and then divide by the encoder ticks per motor rev and then divide by the gear ratio and then multiply by 360 to get the module angle in degrees (you may have to experiment with the +/- sign). You can then feed this module angle into your steering control rather than the absolute encoder.

If you can get this to work, then you can work backward on de-bugging how to get the absolute encoder to work.

A good way to do this would be to display both the motor encoder calculated angle and the absolute encoder angle on the driverstation screen and see if the cancoder values are matching the motor encoder calculated module angles. Keep in mind that there may be an offset between the two that you will need to zero out. Most generic code has an offset value for each module that is set in the initialization process.

Some more detail on the offset, hopefully someone with better knowledge can jump in with more detail as needed.

The CANCoder uses the magnet in the shaft, reads the magnetic field to tell which direction it is facing, and reports the angle. But depending on what angle the magnet was installed in, what angle the encoder is at (notice they are all installed the same direction on each module, so the direction of the encoder is different on each module when compared to the “front” of the robot.)

So you need a way to correct for this. If you point all your wheels forward, the encoders will not all read 0, they will read something like 15, 87, 43, 254. But your software is likely expecting “forward” to be 0 on the encoders. So you need to account for this difference. Start by lining all your wheels up pointing forward, then do one of two things…

  1. Connect to the CANCoder with the CTRE software (Phoenix Tuner I think?) and I think yo ucan read and set the offest in there somehow, though we did not do it this way. I’ve read of people having issues in the past doing this way, so we opted to go with option 2 for now (this is our first swerve too!) These issues moght have all been fixed, but we didn’t have time to test them before an offseason competition last week.

  2. Find a way to read the encoder values when the robot is running. We put them on the dashboard, but you could use a System.out.println as well. Get the values, hard code them in your program and use the value to correct the value read from the encoder. For instance, if the encoder reads 17 when the wheel is straight, then every time you read the encoder value, subtract 17 from the value to get it’s wheel relative value. 17 - 17 is 0, so you’re pointed forward. 107 - 17 is 90, so you’re pointed right, etc. It gets tricky when the value wraps around, for instance if the encoder reads 5, 5 - 17 is -12, so then you need to do some more math to get it to read 348, which is want you want. Basically if it’s less than 0, add 360. If it’s greater than 0, subtract 360 and you should be good.

I hope that’s a clear explanation of what I mean by setting the offsets, if you need more help with actually implementing that, hopefully someone else can help more. I’m good with the theory, not so much with the implementations at this point.

To confirm, the issue you are having is the steering for each of the swerve modules?

Focus on one of the modules only, and choose one with a working CANcoder. Have the robot up on some kind of support so it is not going to move, but also so that everything can turn freely. Since you are using NEO/SPARK MAX and CANcoder, you will have to close the feedback loop in code that runs on the roboRIO. I’d recommend you do this all the time, and not use PID on the SPARK MAX for this at all. But, some code does use the SPARK MAX to help with the position control. Did you write your own code, or are you using code you got from somewhere? Are you trying to do PID control on the SPARK MAX, or on the roboRIO?

Since you have to be able to read the CANcoder angle from the roboRIO, start by just doing this only, and not even trying to run the motor. Does the steering angle change when you rotate the module? You should work on this until you know that this is working correctly, then you can add the motor and PID into things. This is also a good time to make sure you have the offset or zero position correctly set.

Once you know the CANcoder is set up correctly, check to be sure that when you tell the motor to go forward, the sensor angle is increasing and the swerve modules are turning anti-clockwise (as viewed from above). Once you have this all set up properly, it shouldn’t be too hard to tune your PID.

We first aligned the wheel “manually” (through programming), correcting the individual angle of each wheel. We still had a slight unevenness, so we started correcting the values using the PID, taking into account the value of each wheel. We are currently correcting the wheel manually, aligning the wheels in front of the robot by taking the offset of each Cancoder to align the wheels with each other.

We are controlling the PID through RoboRio. The loop is now closed and the robot is suspended. In fact, in the meantime of sending this message we managed to correct the initial value of the wheels to zero, aligning all the wheels in front of the robot. Everything seems to be fine.

1 Like

This is the link to our latest test. The lower right wheel has a slight unevenness as its value was not exactly 0 but 0.00888… By the way, the PID is not correcting immediately with the movement of the joystick, we make a small movement and then it aligns, only then we make the wheel rotate

I don’t know if I made myself clear. Basically, our PID never reaches the desired point. If the wheels are pointing to the right and we turn forward, they never go completely forward. They just start rotating and stop translating diagonally, but when you release the joystick, the PID finally adjusts the position forward.

The video and explanation are very helpful. Thanks for sending these!

It’s hard to be sure without being there, but it looks to me as though you are pretty close. One area that could be an issue here is tuning your PID constants.

Personally, I prefer to use ProfiledPIDController instead of PIDController (see here). In my experience, it’s much easier to tune ProfiledPIDController and it performs better. You can tune things with the robot suspended in the air and have the same tuning settings work on the ground, with carpet, concrete, etc. If you use PIDController, I have seen where tuning things to work well in one of these situations doesn’t work very well on a different surface, or if the weight of the robot changes or isn’t the same on every wheel.

On our swerve robots, we have used 0 (zero) for the “I” and “D” constants, so this part of the tuning is very easy. ProfiledPIDController lets you set a much more aggressive (higher) “P” value, which helps to make things very responsive. But, with ProfiledPIDController, you also have to provide maximum velocity and maximum acceleration constants.

Getting these two isn’t hard – it’s better than having to find “I” and “D” – but you can pretty easily see the maximum velocity and then just try a few different guestimates for maximum acceleration. On our swerve robots (SDS MK4i and NEO), we’ve been using these values:

kTurningPositionMaxVelocity = 1250.0_deg_per_s;
kTurningPositionMaxAcceleration = 12500.0_deg_per_s_sq;
kTurningPositionP = 0.005;
kTurningPositionF = 0.003;

The “F” constant is for feedforward and isn’t really needed. No matter what, you have to pay a lot of attention to the units. We measure our turning angles in degrees, so these constants are using degrees also.

If you don’t want to try ProfiledPIDController, you probably need to work on tuning your PID constants. Just be careful because you may tune them very well to work when the robot is suspended, only to find they don’t work very well when you put it on the ground.

That’s exactly what we were doing. Now the wheel alignment is correct, but the delay between the first joystick movement and the wheel alignment is not. Another video of how the delay works. The video link:
WhatsApp Video 2023-12-22 at 2.21.56 PM.mp4 - Google Drive

This is the kind of thing that’s hard to debug remotely. You seem to be pretty close, but the delay is odd. It could be PID tuning (especially if you are using a non-zero “I” term), but it could also be something else. It would help if you could send a link to your code.

If you can’t easily do this, another thing you might try is searching here (on Chief) to look for other teams who have had similar problems, to see the suggestions and what it was that fixed these. I’d encourage you to do that in any case.

Here is our code so you can take a look, sorry for the delay

OK, so you are using YAGSL. Did you also start from the YAGSL-Example (GitHub - BroncBotz3481/YAGSL-Example: Yet Another General Swerve Library Example Project)? I’m not very familiar with this code (and there’s a lot of it), so you’re probably better off if someone who has used it responds.

I’ll have a look, but it’s a busy time and I didn’t find anything just now (after a fairly quick look). I’d make sure you are calling drive() every iteration of the main loop, and double check your PID (but if the constants are close to what was there in the example, they are probably OK).

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