From ffa53f14e55d998f9706422c87b8b0989a347c5f Mon Sep 17 00:00:00 2001 From: Alibek Omarov Date: Wed, 8 Apr 2026 11:31:01 +0500 Subject: [PATCH] engine: platform: sdl2: implement continuous background recalibration for gyroscope --- engine/platform/sdl2/joy_sdl2.c | 80 ++++++++++++++++++++++++--------- 1 file changed, 58 insertions(+), 22 deletions(-) diff --git a/engine/platform/sdl2/joy_sdl2.c b/engine/platform/sdl2/joy_sdl2.c index 99e47aa7..d7f4945d 100644 --- a/engine/platform/sdl2/joy_sdl2.c +++ b/engine/platform/sdl2/joy_sdl2.c @@ -52,15 +52,16 @@ static SDL_GameController *g_current_gamepad; static SDL_GameController **g_gamepads; static size_t g_num_gamepads; -#define CALIBRATION_TIME 10.0f +#define CALIBRATION_TIME 5.0f static struct { - float time; - vec3_t data; - vec3_t calibrated_values; - float data_rate; - int samples; + float time; + vec3_t data; + vec3_t calibrated_values; + float data_rate; + int samples; + qboolean continuous; // true after first successful calibration } gyrocal; static void SDLash_RestartCalibration( void ) @@ -77,7 +78,7 @@ static void SDLash_RestartCalibration( void ) if( !gyrocal.data_rate ) gyrocal.data_rate = 10.0f; - Con_Printf( "Starting gyroscope calibration at %g data rate...\n", gyrocal.data_rate ); + Con_Printf( S_NOTE "Starting gyroscope calibration at %g data rate for %g seconds...\n", gyrocal.data_rate, CALIBRATION_TIME ); } static void SDLash_FinalizeCalibration( void ) @@ -87,14 +88,53 @@ static void SDLash_FinalizeCalibration( void ) // we waited for few seconds and got too few samples if( gyrocal.samples <= min_samples ) { - Joy_SetCalibrationState( JOY_FAILED_TO_CALIBRATE ); - Con_Printf( "Calibration failed, got samples %d < %d\n", gyrocal.samples, min_samples ); - return; + if( !gyrocal.continuous ) + { + Joy_SetCalibrationState( JOY_FAILED_TO_CALIBRATE ); + Con_Printf( S_ERROR "Calibration failed, got samples %d < %d\n", gyrocal.samples, min_samples ); + gyrocal.time = 0.0f; + return; + } + // Con_Reportf( S_WARN "Continuous calibration: too few samples (%d < %d), retrying\n", gyrocal.samples, min_samples ); + } + else + { + VectorScale( gyrocal.data, 1.0f / gyrocal.samples, gyrocal.calibrated_values ); + Joy_SetCalibrationState( JOY_CALIBRATED ); + if( !gyrocal.continuous ) + Con_Printf( "Calibration done. Result: %f %f %f at %d samples\n", gyrocal.calibrated_values[0], gyrocal.calibrated_values[1], gyrocal.calibrated_values[2], gyrocal.samples ); + // else + // Con_Reportf( "Continuous calibration done. Result: %f %f %f at %d samples\n", gyrocal.calibrated_values[0], gyrocal.calibrated_values[1], gyrocal.calibrated_values[2], gyrocal.samples ); + gyrocal.continuous = true; } - VectorScale( gyrocal.data, 1.0f / gyrocal.samples, gyrocal.calibrated_values ); - Joy_SetCalibrationState( JOY_CALIBRATED ); - Con_Printf( "Calibration done. Result: %f %f %f at %d samples\n", gyrocal.calibrated_values[0], gyrocal.calibrated_values[1], gyrocal.calibrated_values[2], gyrocal.samples ); + // schedule next calibration window + VectorClear( gyrocal.data ); + gyrocal.samples = 0; + gyrocal.time = host.realtime + CALIBRATION_TIME; +} + +static void SDLash_AccumulateCalibrationData( vec3_t data ) +{ + // for continuous background calibration only listen for noise + // by comparing it with calibrated values + // + // for first calibration this might be hurtful as device might + // output offset data + if( gyrocal.continuous ) + { + vec3_t calibrated; + VectorSubtract( data, gyrocal.calibrated_values, calibrated ); + + if( VectorLength( calibrated ) > 0.1f ) + return; + } + + VectorAdd( gyrocal.data, data, gyrocal.data ); + gyrocal.samples++; + + if( !gyrocal.continuous ) + Joy_SetCalibrationState( JOY_CALIBRATING ); } static void SDLash_GameControllerAddMappings( const char *name ) @@ -239,17 +279,13 @@ static void SDLash_GameControllerSensorUpdate( SDL_ControllerSensorEvent sensor if( gyrocal.time != 0.0f ) { if( host.realtime > gyrocal.time ) - { SDLash_FinalizeCalibration(); - gyrocal.time = 0.0f; - } else - { - VectorAdd( gyrocal.data, sensor.data, gyrocal.data ); - gyrocal.samples++; - Joy_SetCalibrationState( JOY_CALIBRATING ); - } - return; + SDLash_AccumulateCalibrationData( sensor.data ); + + // block gyro events only during initial calibration + if( !gyrocal.continuous ) + return; } VectorSubtract( sensor.data, gyrocal.calibrated_values, data );