Quick answer: Pygame joystick.get_axis returning small non-zero values at rest? Sticks have asymmetric deadzones - apply per-axis and per-direction thresholds.

Player character drifts when no input given. Axis reads 0.05 at rest, below the player's 'pressed' threshold.

Per-axis deadzone

def deadzone(v, dz=0.15):
  return 0 if abs(v) < dz else v

Linear deadzone. 15% is generous; tune per controller.

Or radial deadzone

Treat (x, y) as a vector; deadzone the magnitude. Better diagonal feel.

Calibrate on first use

Read axes at startup; assume rest position. Subtract from all subsequent reads. Pads with stick drift get auto-corrected.

“Gamepads have analog imperfection. Deadzones are the lie that makes the imperfection invisible.”

Build the calibration flow as a one-time setup. Players appreciate the polish; drift-bug reports drop to near zero.

Related reading