Conversation
Major improvements to mouse movement quality: 1. **Fixed drift issue**: Changed from acceleration-based to angle-based control - Old: integrated acceleration → velocity → position (double integration = rapid drift) - New: use orientation angles (pitch/roll) directly for velocity - No more continuous drift when holding device still 2. **Fixed jankiness**: Added exponential smoothing filter - Smooths raw angle inputs with alpha=0.3 (30% new, 70% old) - Reduces jitter while maintaining responsiveness 3. **Better dead zone**: Applied to tilt angles instead of acceleration - Ignores tilts below 3 degrees (was 0.05g acceleration) - More effective at filtering unintentional movements 4. **Improved sensitivity**: Updated to 8.0 pixels/degree - Clear units: tilt angle → cursor speed - More intuitive tuning (was using acceleration units) 5. **Optimized AHRS fusion parameters**: - Reduced gain to 0.5 for better stability - Increased acceleration rejection to 20.0 - Better suited for slow, deliberate tilt movements Technical details: - driver/src/uinput.c: Rewrite process_sensor_data() to use Euler angles - driver/src/main.c: Update config defaults (sensitivity, dead_zone units) - Movement now smooth, predictable, and drift-free
There was a problem hiding this comment.
Pull Request Overview
This PR refactors the mouse movement control from an acceleration-based system to an angle-based system to eliminate drift and improve smoothness. The key changes include using device orientation angles (pitch/roll) directly instead of integrating acceleration, adding exponential smoothing to reduce jitter, and updating configuration defaults for the new control scheme.
Key changes:
- Switched from double-integration of acceleration to direct angle-based control using Euler angles from AHRS quaternion
- Added exponential smoothing filter (alpha=0.3) to velocity calculations
- Updated dead zone to operate on tilt angles (3°) instead of acceleration (0.05g)
Reviewed Changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| driver/src/uinput.c | Major rewrite of process_sensor_data() to use orientation angles instead of linear acceleration, added smoothed velocity fields and exponential smoothing filter |
| driver/src/main.c | Updated configuration defaults: movement_sensitivity from 2.0 to 8.0, dead_zone from 0.05 to 3.0 with updated units and comments |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| syslog(LOG_INFO, "Angles: Roll:%.1f° Pitch:%.1f° Yaw:%.1f° | Vel(%.1f, %.1f) px/s | dt:%.4f", | ||
| euler.angle.roll, euler.angle.pitch, euler.angle.yaw, | ||
| world_acceleration.axis.x, world_acceleration.axis.y, world_acceleration.axis.z, dt); | ||
| } | ||
|
|
||
| // Apply dead zone to filter small movements (in g units) | ||
| float dead_zone_g = config.dead_zone; // e.g., 0.03 g | ||
| if (fabsf(world_acceleration.axis.x) < dead_zone_g) world_acceleration.axis.x = 0.0f; | ||
| if (fabsf(world_acceleration.axis.y) < dead_zone_g) world_acceleration.axis.y = 0.0f; | ||
|
|
||
| // Map world-space acceleration to cursor velocity | ||
| // World X acceleration → horizontal cursor movement | ||
| // World Y acceleration → vertical cursor movement | ||
| // Z acceleration ignored (vertical in world frame) | ||
| float cursor_vel_x = world_acceleration.axis.x * config.movement_sensitivity; // World X → Screen X | ||
| float cursor_vel_y = -world_acceleration.axis.y * config.movement_sensitivity; // World Y → Screen Y (inverted) | ||
|
|
||
| // Integrate velocity to position | ||
| fusion_state.cursor_x += cursor_vel_x * dt; | ||
| fusion_state.cursor_y += cursor_vel_y * dt; | ||
|
|
||
| // Debug velocity and accumulation | ||
| if (debug_count % 10 == 0) { | ||
| syslog(LOG_INFO, "VEL: (%.2f, %.2f) px/s | cursor_accum: (%.2f, %.2f) | sens:%.1f deadzone:%.3f g", | ||
| cursor_vel_x, cursor_vel_y, | ||
| fusion_state.cursor_x, fusion_state.cursor_y, | ||
| config.movement_sensitivity, dead_zone_g); | ||
| fusion_state.smoothed_vel_x, fusion_state.smoothed_vel_y, dt); |
There was a problem hiding this comment.
Inconsistent velocity units in the log message. The comment says "px/s" (pixels per second) but based on the actual code calculation, smoothed_vel_x and smoothed_vel_y are in pixels (not pixels/second) due to the unit mismatch bug. Either fix the underlying bug or update this logging to reflect the actual units.
| if (++log_count % 50 == 0) { | ||
| syslog(LOG_INFO, "FUSION Angular Vel: (%.2f, %.2f) | Cursor: (%.2f, %.2f) -> dx:%d dy:%d", | ||
| cursor_vel_x, cursor_vel_y, | ||
| syslog(LOG_INFO, "Movement: Vel(%.1f, %.1f) px/s | Accum(%.2f, %.2f) | Delta dx:%d dy:%d", |
There was a problem hiding this comment.
Same unit inconsistency as in the debug log above - the "px/s" label is incorrect given the current implementation. This should match the actual units of the variables.
| syslog(LOG_INFO, "Movement: Vel(%.1f, %.1f) px/s | Accum(%.2f, %.2f) | Delta dx:%d dy:%d", | |
| syslog(LOG_INFO, "Movement: Vel(%.1f, %.1f) px/packet | Accum(%.2f, %.2f) | Delta dx:%d dy:%d", |
| .gain = 0.5f, // Moderate gain (balance speed vs stability) | ||
| .gyroscopeRange = 2000.0f, // ±2000 degrees/s range | ||
| .accelerationRejection = 10.0f, // Lower rejection for mouse movements | ||
| .accelerationRejection = 20.0f, // Moderate rejection (filter fast movements) |
There was a problem hiding this comment.
The comment says "Moderate rejection (filter fast movements)" but accelerationRejection is used to reject accelerometer readings that deviate from gravity (indicating external acceleration). The higher the value, the more it trusts the gyroscope over the accelerometer. The comment is misleading as it suggests this filters fast movements, when it actually filters non-gravitational acceleration.
Consider clarifying: // Moderate rejection (trust gyro more during acceleration)
| .accelerationRejection = 20.0f, // Moderate rejection (filter fast movements) | |
| .accelerationRejection = 20.0f, // Moderate rejection (trust gyro more during acceleration) |
| fusion_state.cursor_x += fusion_state.smoothed_vel_x * dt; | ||
| fusion_state.cursor_y += fusion_state.smoothed_vel_y * dt; |
There was a problem hiding this comment.
Unit mismatch: The comment at line 178 says the mapping produces "pixels/second", but the calculation roll * config.movement_sensitivity produces pixels (degrees × pixels/degree = pixels), not pixels/second. Then integrating with dt at line 190 gives incorrect units (pixels × seconds).
Either:
- Remove the
* dtmultiplication at lines 190-191, treating the angles as direct position offsets - OR change the sensitivity units to pixels/second/degree and update the comment at main.c:15 accordingly
The first option is likely what was intended based on the comment "Pixels per degree of tilt" in main.c.
| fusion_state.cursor_x += fusion_state.smoothed_vel_x * dt; | |
| fusion_state.cursor_y += fusion_state.smoothed_vel_y * dt; | |
| fusion_state.cursor_x += fusion_state.smoothed_vel_x; | |
| fusion_state.cursor_y += fusion_state.smoothed_vel_y; |
Major improvements to mouse movement quality:
Fixed drift issue: Changed from acceleration-based to angle-based control
Fixed jankiness: Added exponential smoothing filter
Better dead zone: Applied to tilt angles instead of acceleration
Improved sensitivity: Updated to 8.0 pixels/degree
Optimized AHRS fusion parameters:
Technical details: