Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
07460ea
Fixed int16 reconstruction in IMU reading.
GarryBGoode Jun 7, 2025
8eb8cfb
Added new gyro absolute calculation, runs in 1kHz.
GarryBGoode Jun 8, 2025
429f5d1
Fixed IMU not ramping between 2 sources for z axis (roll) motion.
GarryBGoode Jun 8, 2025
fe28cde
Switched doubles to floats.
GarryBGoode Jun 10, 2025
7133f5b
Updated config version
GarryBGoode Jun 10, 2025
335801f
More double to float
GarryBGoode Jun 10, 2025
29ae6a1
Merge branch 'main' of github.com:GarryBGoode/alpakka_firmware into i…
GarryBGoode Jun 14, 2025
a14e913
Merge branch 'inputlabs:main' into imu_gyro_update
GarryBGoode Jun 22, 2025
e513da1
Refined IMU switch-over logic, it's not per-axis, but vector length b…
GarryBGoode Jun 27, 2025
cfead9f
Merge branch 'imu_gyro_update' of github.com:GarryBGoode/alpakka_firm…
GarryBGoode Jun 27, 2025
318aec3
Merge branch 'inputlabs:main' into imu_gyro_update
GarryBGoode Jun 27, 2025
7f81416
Merge branch 'imu_gyro_update' of github.com:GarryBGoode/alpakka_firm…
GarryBGoode Jun 27, 2025
3039747
Merge branch 'main' into imu_gyro_update
GarryBGoode Jul 6, 2025
82bd962
Changed gyro X sensitivity from 2 back to 1
GarryBGoode Jul 6, 2025
ce8e557
Added printing of imu weights. Added missing Z axis reporting for abs…
GarryBGoode Jul 13, 2025
b3e55fd
Powf(x,2) instead of x*x is a crime
GarryBGoode Jul 22, 2025
986f01d
Added code to cycle through HID reports (keyboard, mouse, gamepad) ev…
GarryBGoode Jul 22, 2025
07f9d3b
Lowered tick frequency to 500Hz due to some limitation in wireless mo…
GarryBGoode Aug 2, 2025
38f1ade
Added function to monitor idle state in wireless mode, and automatica…
GarryBGoode Aug 2, 2025
0f79919
Removed TICK_FREQUENCY for dongle mode. Dongle will run as fast as it…
GarryBGoode Aug 9, 2025
1916932
Some more double->float conversion in thumbstick
GarryBGoode Aug 9, 2025
6f57dc0
Merge branch 'inputlabs:main' into imu_gyro_update
GarryBGoode Aug 20, 2025
6a1203c
Added screening logic to detect outliers in IMU gyro signal. Might he…
GarryBGoode Oct 27, 2025
66bb474
Merge install.sh update
GarryBGoode Oct 27, 2025
15a12bd
Merge branch 'inputlabs:main' into imu_gyro_update
GarryBGoode Apr 12, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ target_sources(${PROJECT} PUBLIC
src/profiles/racing.c
src/profiles/rts.c
src/rotary.c
src/rotation_fast.c
src/self_test.c
src/thanks.c
src/thumbstick.c
Expand Down
60 changes: 56 additions & 4 deletions src/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,18 @@ void config_write_init() {
.offset_accel_1_x = 0,
.offset_accel_1_y = 0,
.offset_accel_1_z = 0,
.stddev_gyro_0_x = 1.0,
.stddev_gyro_0_y = 1.0,
.stddev_gyro_0_z = 1.0,
.stddev_gyro_1_x = 1.0,
.stddev_gyro_1_y = 1.0,
.stddev_gyro_1_z = 1.0,
.stddev_accel_0_x = 1.0,
.stddev_accel_0_y = 1.0,
.stddev_accel_0_z = 1.0,
.stddev_accel_1_x = 1.0,
.stddev_accel_1_y = 1.0,
.stddev_accel_1_z = 1.0,
.log_level = 0,
.log_mask = 0,
.long_calibration = 0,
Expand Down Expand Up @@ -238,6 +250,26 @@ void config_print() {
config_cache.offset_accel_1_y,
config_cache.offset_accel_1_z
);
info(" stddev_gyro_0 x=%.2f y=%.2f z=%.2f\n",
config_cache.stddev_gyro_0_x,
config_cache.stddev_gyro_0_y,
config_cache.stddev_gyro_0_z
);
info(" stddev_gyro_1 x=%.2f y=%.2f z=%.2f\n",
config_cache.stddev_gyro_1_x,
config_cache.stddev_gyro_1_y,
config_cache.stddev_gyro_1_z
);
info(" stddev_accel_0 x=%.2f y=%.2f z=%.2f\n",
config_cache.stddev_accel_0_x,
config_cache.stddev_accel_0_y,
config_cache.stddev_accel_0_z
);
info(" stddev_accel_1 x=%.2f y=%.2f z=%.2f\n",
config_cache.stddev_accel_1_x,
config_cache.stddev_accel_1_y,
config_cache.stddev_accel_1_z
);
}

void config_print_minimal() {
Expand Down Expand Up @@ -265,7 +297,7 @@ void config_set_thumbstick_offset(float lx, float ly, float rx, float ry) {
config_cache_synced = false;
}

void config_set_gyro_offset(double ax, double ay, double az, double bx, double by, double bz) {
void config_set_gyro_offset(float ax, float ay, float az, float bx, float by, float bz) {
config_cache.offset_gyro_0_x = ax,
config_cache.offset_gyro_0_y = ay,
config_cache.offset_gyro_0_z = az,
Expand All @@ -275,7 +307,7 @@ void config_set_gyro_offset(double ax, double ay, double az, double bx, double b
config_cache_synced = false;
}

void config_set_accel_offset(double ax, double ay, double az, double bx, double by, double bz) {
void config_set_accel_offset(float ax, float ay, float az, float bx, float by, float bz) {
config_cache.offset_accel_0_x = ax,
config_cache.offset_accel_0_y = ay,
config_cache.offset_accel_0_z = az,
Expand All @@ -285,6 +317,26 @@ void config_set_accel_offset(double ax, double ay, double az, double bx, double
config_cache_synced = false;
}

void config_set_gyro_stddev(float ax, float ay, float az, float bx, float by, float bz) {
config_cache.stddev_gyro_0_x = ax,
config_cache.stddev_gyro_0_y = ay,
config_cache.stddev_gyro_0_z = az,
config_cache.stddev_gyro_1_x = bx,
config_cache.stddev_gyro_1_y = by,
config_cache.stddev_gyro_1_z = bz,
config_cache_synced = false;
}

void config_set_accel_stddev(float ax, float ay, float az, float bx, float by, float bz) {
config_cache.stddev_accel_0_x = ax,
config_cache.stddev_accel_0_y = ay,
config_cache.stddev_accel_0_z = az,
config_cache.stddev_accel_1_x = bx,
config_cache.stddev_accel_1_y = by,
config_cache.stddev_accel_1_z = bz,
config_cache_synced = false;
}

void config_tune_update_leds() {
if (config_tune_mode == PROC_TUNE_OS) {
led_static_mask(LED_UP);
Expand Down Expand Up @@ -457,7 +509,7 @@ uint8_t config_get_touch_sens_value(uint8_t index) {
return config_cache.sens_touch_values[index];
}

double config_get_mouse_sens_value(uint8_t index) {
float config_get_mouse_sens_value(uint8_t index) {
return config_cache.sens_mouse_values[index];
}

Expand All @@ -473,7 +525,7 @@ void config_set_touch_sens_values(uint8_t* values) {
config_cache_synced = false;
}

void config_set_mouse_sens_values(double* values) {
void config_set_mouse_sens_values(float* values) {
config_cache.sens_mouse_values[0] = values[0];
config_cache.sens_mouse_values[1] = values[1];
config_cache.sens_mouse_values[2] = values[2];
Expand Down
2 changes: 1 addition & 1 deletion src/ctrl.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ void ctrl_config_set(Ctrl_cfg_type key, uint8_t preset, uint8_t values[5]) {
}
else if (key == SENS_MOUSE) {
// Scaled by 10 since the USB communication works with integers.
double values_fmt[] = {
float values_fmt[] = {
values[0] / 10.0,
values[1] / 10.0,
values[2] / 10.0
Expand Down
89 changes: 68 additions & 21 deletions src/gyro.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,16 @@
#include "pin.h"
#include "touch.h"
#include "vector.h"
#include "rotation_fast.h"

double sensitivity_multiplier;
float sensitivity_multiplier;

uint8_t world_init = 0;
Vector world_top;
Vector world_fw;
Vector world_right;
Vector accel_smooth;
RotationStateVector rotation_state;

void gyro_update_sensitivity() {
uint8_t preset = config_get_mouse_sens_preset();
Expand Down Expand Up @@ -84,7 +86,7 @@ void gyro_absolute_output(float value, uint8_t *actions, bool *pressed) {
}
}

void gyro_incremental_output(double value, uint8_t *actions) {
void gyro_incremental_output(float value, uint8_t *actions) {
for(uint8_t i=0; i<4; i++) {
uint8_t action = actions[i];
if (action == MOUSE_X) hid_mouse_move(value, 0);
Expand All @@ -94,9 +96,9 @@ void gyro_incremental_output(double value, uint8_t *actions) {
}
}

double hssnf(double t, double k, double x) {
double a = x - (x * k);
double b = 1 - (x * k * (1/t));
float hssnf(float t, float k, float x) {
float a = x - (x * k);
float b = 1 - (x * k * (1/t));
return a / b;
}

Expand Down Expand Up @@ -148,32 +150,77 @@ void Gyro__report_absolute(Gyro *self) {
// printf("\r%6.1f %6.1f %6.1f", x*100, y*100, z*100);
}

void Gyro__report_absolute_fast(Gyro *self){
static uint32_t time_us_lock_prev = 0;
uint32_t time_us = time_us_32();
uint32_t dt_us = time_us - time_us_lock_prev; // Safe for overflow with unsigned arithmetic
time_us_lock_prev = time_us;
Vector gyro = imu_read_gyro();
Vector accel = imu_read_accel();
// gyro axis convention is different from physical IMU axis convention.
float gyro_arr[3] = {gyro.y * GYRO_SENS_RADPS_500,
gyro.z * GYRO_SENS_RADPS_500,
-gyro.x * GYRO_SENS_RADPS_500};
// Acceleration axis convention is unchanged from physical IMU axis convention.
float accel_arr[3] = {accel.x * ACCEL_SENS_2G,
accel.y * ACCEL_SENS_2G,
accel.z * ACCEL_SENS_2G};
update_rotation_state(&rotation_state, gyro_arr, accel_arr, dt_us / 1000000.0f);

// Output calculation.
// physically, X points to the right of the controller
float x = (atan2f(rotation_state.ux,rotation_state.uz)) / M_PI;
float y = -(asinf(rotation_state.uy)) / M_PI;
float z = rotation_state.phi / M_PI;

x = constrain(x * 1.1, -1, 1); // Additional saturation.
x = ramp(x, self->absolute_x_min/180, self->absolute_x_max/180); // Adjust range.
y = ramp(y, self->absolute_y_min/180, self->absolute_y_max/180); // Adjust range.
// Output mapping.
if (x >= 0) gyro_absolute_output( x, self->actions_x_pos, &(self->pressed_x_pos));
else gyro_absolute_output(-x, self->actions_x_neg, &(self->pressed_x_neg));
if (y >= 0) gyro_absolute_output( y, self->actions_y_pos, &(self->pressed_y_pos));
else gyro_absolute_output(-y, self->actions_y_neg, &(self->pressed_y_neg));
if (z >= 0) gyro_absolute_output( z, self->actions_z_pos, &(self->pressed_z_pos));
else gyro_absolute_output(-z, self->actions_z_neg, &(self->pressed_z_neg));

}


void Gyro__report_incremental(Gyro *self) {
static double sub_x = 0;
static double sub_y = 0;
static double sub_z = 0;
static float sub_x = 0;
static float sub_y = 0;
static float sub_z = 0;
// Read gyro values.
Vector imu_gyro = imu_read_gyro();
double x = imu_gyro.x * CFG_GYRO_SENSITIVITY_X * sensitivity_multiplier;
double y = imu_gyro.y * CFG_GYRO_SENSITIVITY_Y * sensitivity_multiplier;
double z = imu_gyro.z * CFG_GYRO_SENSITIVITY_Z * sensitivity_multiplier;
// Additional processing.
double t = 1.0;
double k = 0.5;
float x = imu_gyro.x * CFG_GYRO_SENSITIVITY_X * sensitivity_multiplier;
float y = imu_gyro.y * CFG_GYRO_SENSITIVITY_Y * sensitivity_multiplier;
float z = imu_gyro.z * CFG_GYRO_SENSITIVITY_Z * sensitivity_multiplier;


// compensate tick frequency.
x *= (float)REFERENCE_TICK_FREQUENCY/(float)CFG_TICK_FREQUENCY;
y *= (float)REFERENCE_TICK_FREQUENCY/(float)CFG_TICK_FREQUENCY;
z *= (float)REFERENCE_TICK_FREQUENCY/(float)CFG_TICK_FREQUENCY;

//Additional processing.
float t = CFG_IMU_DEADZONE*0;
float k = CFG_IMU_DEADZONE_STRENGTH;
if (x > 0 && x < t) x = hssnf(t, k, x);
else if (x < 0 && x > -t) x = -hssnf(t, k, -x);
if (y > 0 && y < t) y = hssnf(t, k, y);
else if (y < 0 && y > -t) y = -hssnf(t, k, -y);
if (z > 0 && z < t) z = hssnf(t, k, z);
else if (z < 0 && z > -t) z = -hssnf(t, k, -z);

// Reintroduce subpixel leftovers.
x += sub_x;
y += sub_y;
z += sub_z;
// Round down and save leftovers.
sub_x = modf(x, &x);
sub_y = modf(y, &y);
sub_z = modf(z, &z);
sub_x = modff(x, &x);
sub_y = modff(y, &y);
sub_z = modff(z, &z);
// Report.
if (x >= 0) gyro_incremental_output( x, self->actions_x_pos);
else gyro_incremental_output(-x, self->actions_x_neg);
Expand Down Expand Up @@ -217,21 +264,21 @@ void Gyro__reset(Gyro *self) {
self->pressed_z_neg = false;
}

void Gyro__config_x(Gyro *self, double min, double max, Actions neg, Actions pos) {
void Gyro__config_x(Gyro *self, float min, float max, Actions neg, Actions pos) {
self->absolute_x_min = min;
self->absolute_x_max = max;
memcpy(self->actions_x_neg, neg, ACTIONS_LEN);
memcpy(self->actions_x_pos, pos, ACTIONS_LEN);
}

void Gyro__config_y(Gyro *self, double min, double max, Actions neg, Actions pos) {
void Gyro__config_y(Gyro *self, float min, float max, Actions neg, Actions pos) {
self->absolute_y_min = min;
self->absolute_y_max = max;
memcpy(self->actions_y_neg, neg, ACTIONS_LEN);
memcpy(self->actions_y_pos, pos, ACTIONS_LEN);
}

void Gyro__config_z(Gyro *self, double min, double max, Actions neg, Actions pos) {
void Gyro__config_z(Gyro *self, float min, float max, Actions neg, Actions pos) {
self->absolute_z_min = min;
self->absolute_z_max = max;
memcpy(self->actions_z_neg, neg, ACTIONS_LEN);
Expand All @@ -246,7 +293,7 @@ Gyro Gyro_ (
gyro.is_engaged = Gyro__is_engaged;
gyro.report = Gyro__report;
gyro.report_incremental = Gyro__report_incremental;
gyro.report_absolute = Gyro__report_absolute;
gyro.report_absolute = Gyro__report_absolute_fast;
gyro.reset = Gyro__reset;
gyro.config_x = Gyro__config_x;
gyro.config_y = Gyro__config_y;
Expand Down
Loading