@@ -30,7 +30,6 @@ static uint8_t last_button_state = 0;
3030// IMU state with Fusion AHRS
3131typedef struct {
3232 FusionAhrs ahrs ; // Fusion AHRS algorithm
33- FusionQuaternion prev_quaternion ; // Previous quaternion for angular velocity
3433 double t_last ;
3534 float cursor_x , cursor_y ; // Virtual cursor position (accumulated)
3635 int initialized ;
@@ -139,20 +138,19 @@ void process_sensor_data(UInputDevice* device, const SensorPacket* packet) {
139138 // Initialize Fusion AHRS
140139 FusionAhrsInitialise (& fusion_state .ahrs );
141140
142- // Set AHRS settings for optimized mouse control
141+ // Set AHRS settings optimized for fast, accurate mouse control
143142 FusionAhrsSettings settings = {
144143 .convention = FusionConventionNwu , // North-West-Up coordinate system
145- .gain = 0.5f , // Moderate gain for stability
144+ .gain = 1.0f , // Higher gain for faster convergence
146145 .gyroscopeRange = 2000.0f , // ±2000 degrees/s range
147- .accelerationRejection = 90 .0f , // Reject high accelerations
146+ .accelerationRejection = 10 .0f , // Lower rejection for mouse movements
148147 .magneticRejection = 0.0f , // No magnetometer
149- .recoveryTriggerPeriod = 5 * 100 // 5 seconds at 100Hz
148+ .recoveryTriggerPeriod = 2 * 200 // 2 seconds at 200Hz (faster recovery)
150149 };
151150 FusionAhrsSetSettings (& fusion_state .ahrs , & settings );
152151
153152 fusion_state .cursor_x = 0.0f ;
154153 fusion_state .cursor_y = 0.0f ;
155- fusion_state .prev_quaternion = FUSION_IDENTITY_QUATERNION ;
156154 fusion_state .initialized = 1 ;
157155 return ; // Skip first frame
158156 }
@@ -163,59 +161,45 @@ void process_sensor_data(UInputDevice* device, const SensorPacket* packet) {
163161 // Get current quaternion
164162 FusionQuaternion quaternion = FusionAhrsGetQuaternion (& fusion_state .ahrs );
165163
166- // Calculate angular velocity from quaternion difference
167- // This gives us the rotation rate independent of device orientation
164+ // Get linear acceleration (with gravity removed by Fusion)
165+ FusionVector linear_acceleration = FusionAhrsGetLinearAcceleration ( & fusion_state . ahrs );
168166
169- // Manually create conjugate of previous quaternion (negate x,y,z components)
170- FusionQuaternion prev_conjugate = {
171- .element .w = fusion_state .prev_quaternion .element .w ,
172- .element .x = - fusion_state .prev_quaternion .element .x ,
173- .element .y = - fusion_state .prev_quaternion .element .y ,
174- .element .z = - fusion_state .prev_quaternion .element .z
175- };
176-
177- FusionQuaternion quaternion_diff = FusionQuaternionMultiply (quaternion , prev_conjugate );
178-
179- // Extract angular velocity from quaternion difference
180- // Small angle approximation: angular_velocity ≈ 2 * quaternion_vector / dt
181- float angular_vel_x = 2.0f * quaternion_diff .element .x / dt ; // Roll rate
182- float angular_vel_y = 2.0f * quaternion_diff .element .y / dt ; // Pitch rate
183- float angular_vel_z = 2.0f * quaternion_diff .element .z / dt ; // Yaw rate
184-
185- fusion_state .prev_quaternion = quaternion ;
167+ // Transform linear acceleration from device frame to world frame using current orientation
168+ // This makes movement independent of device rotation - move device left = cursor left
169+ FusionMatrix rotation_matrix = FusionQuaternionToMatrix (quaternion );
170+ FusionVector world_acceleration = FusionMatrixMultiplyVector (rotation_matrix , linear_acceleration );
186171
187172 // Debug: log sensor fusion values
188173 static int debug_count = 0 ;
189174 if (++ debug_count % 10 == 0 ) { // Every 10 frames (~200ms)
190175 FusionEuler euler = FusionQuaternionToEuler (quaternion );
191- syslog (LOG_INFO , "FUSION: Roll:%.1f° Pitch:%.1f° Yaw:%.1f° | AngVel (%.2f , %.2f , %.2f ) dt:%.4f" ,
176+ syslog (LOG_INFO , "FUSION: Roll:%.1f° Pitch:%.1f° Yaw:%.1f° | WorldAccel (%.3f , %.3f , %.3f ) dt:%.4f" ,
192177 euler .angle .roll , euler .angle .pitch , euler .angle .yaw ,
193- angular_vel_x , angular_vel_y , angular_vel_z , dt );
178+ world_acceleration . axis . x , world_acceleration . axis . y , world_acceleration . axis . z , dt );
194179 }
195180
196- // Apply dead zone FIRST to filter noise/drift (in degrees/second)
197- float dead_zone_deg_per_sec = config .dead_zone ; // e.g., 0.1 deg/s
198- if (fabsf (angular_vel_x ) < dead_zone_deg_per_sec ) angular_vel_x = 0.0f ;
199- if (fabsf (angular_vel_y ) < dead_zone_deg_per_sec ) angular_vel_y = 0.0f ;
200- if (fabsf (angular_vel_z ) < dead_zone_deg_per_sec ) angular_vel_z = 0.0f ;
181+ // Apply dead zone to filter small movements (in g units)
182+ float dead_zone_g = config .dead_zone ; // e.g., 0.03 g
183+ if (fabsf (world_acceleration .axis .x ) < dead_zone_g ) world_acceleration .axis .x = 0.0f ;
184+ if (fabsf (world_acceleration .axis .y ) < dead_zone_g ) world_acceleration .axis .y = 0.0f ;
201185
202- // Map angular velocity to cursor movement ( velocity-based control)
203- // Yaw (Z) rotation → horizontal cursor movement
204- // Pitch (Y) rotation → vertical cursor movement
205- // Roll (X) is ignored for 2D mouse control
206- float cursor_vel_x = - angular_vel_z * config .movement_sensitivity ; // Yaw → X (negated to fix inversion)
207- float cursor_vel_y = - angular_vel_y * config .movement_sensitivity ; // Pitch → Y (inverted)
186+ // Map world-space acceleration to cursor velocity
187+ // World X acceleration → horizontal cursor movement
188+ // World Y acceleration → vertical cursor movement
189+ // Z acceleration ignored (vertical in world frame)
190+ float cursor_vel_x = world_acceleration . axis . x * config .movement_sensitivity ; // World X → Screen X
191+ float cursor_vel_y = - world_acceleration . axis . y * config .movement_sensitivity ; // World Y → Screen Y (inverted)
208192
209193 // Integrate velocity to position
210194 fusion_state .cursor_x += cursor_vel_x * dt ;
211195 fusion_state .cursor_y += cursor_vel_y * dt ;
212196
213197 // Debug velocity and accumulation
214198 if (debug_count % 10 == 0 ) {
215- syslog (LOG_INFO , "VEL: (%.2f, %.2f) px/s | cursor_accum: (%.2f, %.2f) | sens:%.1f deadzone:%.3f deg/s " ,
199+ syslog (LOG_INFO , "VEL: (%.2f, %.2f) px/s | cursor_accum: (%.2f, %.2f) | sens:%.1f deadzone:%.3f g " ,
216200 cursor_vel_x , cursor_vel_y ,
217201 fusion_state .cursor_x , fusion_state .cursor_y ,
218- config .movement_sensitivity , dead_zone_deg_per_sec );
202+ config .movement_sensitivity , dead_zone_g );
219203 }
220204
221205 // Extract integer deltas for mouse movement
0 commit comments