Skip to content

switch: Fix gyro ZRO handling in IMU sensor updates#15860

Open
alexeev wants to merge 2 commits into
libsdl-org:mainfrom
alexeev:fix-from-release-3.4.x
Open

switch: Fix gyro ZRO handling in IMU sensor updates#15860
alexeev wants to merge 2 commits into
libsdl-org:mainfrom
alexeev:fix-from-release-3.4.x

Conversation

@alexeev

@alexeev alexeev commented Jun 20, 2026

Copy link
Copy Markdown
  • I confirm that I am the author of this code and release it to the SDL project under the Zlib license. This contribution does not contain code from other sources, including code generated by a Large Language Model ("AI").

Description

This PR fixes gyroscope drift handling for Nintendo Switch controllers by applying the calibrated gyroscope zero-rate offsets when reporting live IMU sensor data.

The change is split into two commits:

  1. A small preparatory refactor in LoadIMUCalibration()
  2. The actual gyroscope offset fix in SendSensorUpdate()

1. Preparatory refactor

LoadIMUCalibration() reads factory IMU calibration data first, and then attempts to read user calibration data from SPI flash.

The existing user calibration check relies on pIMUScale still pointing at memory that is updated by the next WriteSubcommand() call:

if (WriteSubcommand(ctx, k_eSwitchSubcommandIDs_SPIFlashRead, (uint8_t *)&readParams, sizeof(readParams), &reply) &&
    (pIMUScale[0] | pIMUScale[1] << 8) == 0xA1B2) {
    pIMUScale = reply->spiReadData.rgucReadData;
    ...
}

This works today because the HID read path uses the same backing buffer, but the sequencing is fragile: the magic value is checked before the pointer is explicitly assigned to the newly returned SPI payload.
The first commit makes this dependency explicit by assigning the user calibration payload pointer before checking the magic value. This is intended as a no-behavior-change cleanup that makes the following bug fix safer and easier to review.

2. Gyroscope offset fix

LoadIMUCalibration() already reads the calibrated gyroscope raw offsets from SPI flash. These values represent the controller's zero-rate offset.

Previously, these raw offset values were only used while computing the gyroscope scale factors, and were not retained for live sensor updates. As a result, SendSensorUpdate() multiplied raw gyroscope samples by the scale factor without first subtracting the calibrated zero-rate offset.

This PR stores the calibrated gyroscope offsets and applies the standard IMU conversion:

(raw_value - offset) * scale

The fix preserves the existing axis remapping and sign conventions in SendSensorUpdate().

Testing

Tested using testcontroller with a Nintendo Switch Pro Controller over USB and Bluetooth on MacOS Tahoe 26.5.1

Before this change, a stationary controller reported a persistent gyroscope bias/drift of roughly 8.5 deg/s.

After this change, with the controller stationary on a flat surface, the reported gyroscope values hover close to zero.

 

Existing Issue(s)

No existing GitHub issue found.

Other

I'd appreciate guidance on forward-porting to main.

@slouken

slouken commented Jun 21, 2026

Copy link
Copy Markdown
Collaborator

This looks good! Can you please retarget the main branch? We'll cherry-pick this to release-3.4.x after merging.

@slouken slouken added this to the 3.4.12 milestone Jun 21, 2026
Dimitri Alexeev added 2 commits June 22, 2026 10:13
…libration. Prevent reading potentially stale memory. No functional changes.
@alexeev alexeev force-pushed the fix-from-release-3.4.x branch from 7b16045 to 84b7408 Compare June 22, 2026 08:53
@alexeev alexeev changed the base branch from release-3.4.x to main June 22, 2026 08:55
@alexeev

alexeev commented Jun 22, 2026

Copy link
Copy Markdown
Author

@slouken, sure, re-targeted to the main and tested. Works as expected:


bugfix-gyro

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants