Swerve Drive Hockey Stopping


Our team is using a swerve drive train this year. We are working on a turntable style mode where the rotation of the turntable (or a joystick) directly maps to the orientation of the robot, but we are having an issue where as the robot is slowing down to a stop, the robot does a “hockey stop” and turns all the wheels diagonally as if it were rotating, causing it to stop extremely quickly. This issue is caused by the fact that the direction is constantly trying to correct itself using the information from the gyro and the turntable, meaning that there will always be some rotational component to our movement. When we are stopping, the strafe component to our movement (calculated from our controller) is zero. This means that the rotation entirely controls the position of each of the wheels, causing it to lock the wheels into the rotation position and “hockey stop” every time.

We have tried several solutions to fix this problem. First, we added a tolerance that told the robot to ignore rotation if it was slowing down and if it was within a certain distance from our target angle. This proved to be mostly ineffective because the robot would rotate a very large amount as it was slowing down, however it will require more testing on our competition robot. The other solution we tried was to add an acceleration/velocity curve that would add in a movement component to our joystick input that is slightly smaller than the robot’s current movement, causing it to slow down over time while maintaining our direction. In practice, this never worked very well, but with some tuning it might work.

We are curious if there are any threads that already exist on this topic and if any other teams have run into this issue.


If it moves sideways it’s a waste of your time!


If I understand the problem right, “slowing down to a stop” means that the control input is zero, but the robot’s current velocity is not zero. The robot adds the necessary rotation to the control input, and turns the wheels appropriately, but this leads to “hockey stopping” when the control input suddenly goes to zero. Is that right?

It sounds like the solution is for the robot to track its current velocity and to use that (rather than the control input) for computing the rotation component. Ideally you would measure this with encoders/accelerometer/gyro, but you can probably model it pretty well and just use a feed-forward model.

This is kind of what you were getting at with the second solution, except that you actually are letting the control input go to zero (so you shouldn’t have any loss of agility). You’re just adapting your turning to what’s really happening, not to the idealized control input.


Another way to phrase the question:

Do swerve drive teams usually run an auxiliary PID loop (or other control loop) to maintain a constant robot heading while driving? We have noticed a very slight drift in the robot heading as we drive around without intentionally rotating.

When we tried to run an auxiliary PID loop, the robot would attempt to rotate even when it is stopped and close to the desired heading (maybe 10 degrees error). So, when we let go of the joystick, the wheels immediately go into 45 degree angles as if they are trying to steer, because there is no translational component to the commanded motion. AKA Hockey Stop. How can we avoid this?


When driving in Teleop, I’d recommend not using a control loop to control the heading since the driver will be much better at correcting than a control loop. Our driver prefers to drive without control loop aid. Unless constructed to a level of impossible perfectness and the wheels are perfectly aligned, the swerve drive will drift slightly and that’s ok.

In any autonomous mode though, it would probably be necessary to implement a control loop (usually only P control) to maintain a heading.

To answer the hockey stop problem see the conditional if(drive == 0) in the following code:

   * This method calculates the optimal driveTalon settings and applies them.
   * @param azimuth -0.5 to 0.5 rotations, measured clockwise with zero being the wheel's zeroed
   *     position
   * @param drive 0 to 1.0 in the direction of the wheel azimuth
  public void set(double azimuth, double drive) {
    // don't reset wheel azimuth direction to zero when returning to neutral
    if (drive == 0) {

    azimuth *= -TICKS; // flip azimuth, hardware configuration dependent

    double azimuthPosition = azimuthTalon.getSelectedSensorPosition(0);
    double azimuthError = Math.IEEEremainder(azimuth - azimuthPosition, TICKS);

    // minimize azimuth rotation, reversing drive if necessary
    isInverted = Math.abs(azimuthError) > 0.25 * TICKS;
    if (isInverted) {
      azimuthError -= Math.copySign(0.5 * TICKS, azimuthError);
      drive = -drive;

    azimuthTalon.set(MotionMagic, azimuthPosition + azimuthError);


Thank you for the response! We will look into doing that.

You mentioned not correcting the robot heading during teleop. Does that mean your control scheme involves controlling the rate of rotation of the robot, instead of the heading directly? So for example pushing the stick to the left will cause it to rotate CCW, rotating faster as the stick moves further from center? That is what we are doing now and it seems to work great.

Our reasoning for attempting to correct for robot heading even in teleop is so that we can do an absolute heading -based control scheme. Where moving the steering stick to the right, for example, will cause the robot to steer so that it is facing the right. And it will maintain that heading until the stick is pushed in a different direction. That obviously requires some gyro-based heading correction. However, if we can’t get it to work we do have a solid fallback option that I mentioned in the previous paragraph.

It was super inspirational to see your swerve modules in the pits at Detroit champs last year; that is a major reason why we are running with swerve drive this year!


We also seem to be experiencing quite a bit of drift. We did have one of our wheels stop spinning halfway through testing which definitely attributed to the problem. However, assuming the drift is still somewhat significant, how well would a Velocity PID loop work for all 4 wheels. Essentially plug in the inverse kinematics outputs of wheel speeds (which outputs 0-1) * max RPM of wheel as the set point.


Thanks and congratulations! I’m glad you guys have gotten your swerve up and running. We’re completely field oriented. We use joysticks: one stick controls yaw (push left, we turn CW, when pushed right, we turn CCW). The other joystick takes the input x and y and translates that to our forward and strafe components (forward is down the field forwards/backwards, strafe is across the field, left/right, regardless of our orientation).


Awesome, that sounds exactly like what we have running right now with field-oriented drive. We are using one Logitech gamepad to get the two joysticks but that’s minor details. Glad to hear that we’re on the right track.


Before trying a control loop, make sure all your wheels are working and that all the wheels are aligned.

You can use the Grapher utility https://github.com/strykeforce/grapher to make sure the motors, talons, and wheels are doing what you think they are. Often if there’s a problem, graphing the Talon data will quickly reveal any problems.