feat(esp_joystick): eliminate joystick ADC jitter

Add power-off memory function for HID mode selection

Close AEG-1578
This commit is contained in:
Liang Hao
2024-06-06 16:34:25 +08:00
parent dbe8ef9c15
commit 6b3993bd03
5 changed files with 125 additions and 38 deletions
@@ -75,7 +75,10 @@ void ble_hid_send_joystick_value(uint16_t joystick_buttons, uint8_t joystick_x,
buffer[3] = (joystick_y) - 1; /* LY */
buffer[4] = (joystick_z); /* RX */
buffer[5] = (joystick_rx) - 1; /* RY */
esp_hidd_dev_input_set(s_ble_hid_param.hid_dev, 0, HID_RPT_ID_CC_GP_IN, buffer, HID_CC_IN_RPT_GP_LEN);
esp_err_t ret = esp_hidd_dev_input_set(s_ble_hid_param.hid_dev, 0, HID_RPT_ID_CC_GP_IN, buffer, HID_CC_IN_RPT_GP_LEN);
if (ret != ESP_OK) {
ESP_LOGE(BLE_HID_TAG, "Failed to send key value via BLE-HID.");
}
return;
}
@@ -98,16 +98,84 @@ esp_err_t rocker_adc_init(void)
return ESP_OK;
}
void get_rocker_adc_value(uint16_t rocker_value[4])
void get_rocker_adc_value_in_game_mode(uint16_t rocker_value[4])
{
adc_oneshot_read(game_mode_adc_handle, LEFT_HOTAS1_ADC_CHAN, &g_left_hotas1_adc_raw[0][0]);
adc_oneshot_read(game_mode_adc_handle, LEFT_HOTAS2_ADC_CHAN, &g_left_hotas2_adc_raw[0][0]);
adc_oneshot_read(game_mode_adc_handle, RIGHT_HOTAS1_ADC_CHAN, &g_right_hotas1_adc_raw[0][0]);
adc_oneshot_read(game_mode_adc_handle, RIGHT_HOTAS2_ADC_CHAN, &g_right_hotas2_adc_raw[0][0]);
if (do_left_hotas1_adc_chan && do_left_hotas2_adc_chan && do_right_hotas1_adc_chan && do_right_hotas2_adc_chan) {
rocker_value[0] = g_left_hotas1_adc_raw[0][0];
rocker_value[1] = g_left_hotas2_adc_raw[0][0];
rocker_value[2] = g_right_hotas1_adc_raw[0][0];
rocker_value[3] = g_right_hotas2_adc_raw[0][0];
for (int i = 0; i < 4; i++) {
rocker_value[i] = 0;
}
int left_hotas1_adc_value[ADC_MEAS_WINDOW_SIZE] = {0};
int left_hotas2_adc_value[ADC_MEAS_WINDOW_SIZE] = {0};
int right_hotas1_adc_value[ADC_MEAS_WINDOW_SIZE] = {0};
int right_hotas2_adc_value[ADC_MEAS_WINDOW_SIZE] = {0};
for (int i = 0; i < ADC_MEAS_WINDOW_SIZE; i++) {
int left_hotas1_value = 0;
int left_hotas2_value = 0;
int right_hotas1_value = 0;
int right_hotas2_value = 0;
for (int j = 0; j < 10; j++) {
adc_oneshot_read(game_mode_adc_handle, LEFT_HOTAS1_ADC_CHAN, &g_left_hotas1_adc_raw[0][0]);
adc_oneshot_read(game_mode_adc_handle, LEFT_HOTAS2_ADC_CHAN, &g_left_hotas2_adc_raw[0][0]);
adc_oneshot_read(game_mode_adc_handle, RIGHT_HOTAS1_ADC_CHAN, &g_right_hotas1_adc_raw[0][0]);
adc_oneshot_read(game_mode_adc_handle, RIGHT_HOTAS2_ADC_CHAN, &g_right_hotas2_adc_raw[0][0]);
if (do_left_hotas1_adc_chan && do_left_hotas2_adc_chan && do_right_hotas1_adc_chan && do_right_hotas2_adc_chan) {
left_hotas1_value += g_left_hotas1_adc_raw[0][0];
left_hotas2_value += g_left_hotas2_adc_raw[0][0];
right_hotas1_value += g_right_hotas1_adc_raw[0][0];
right_hotas2_value += g_right_hotas2_adc_raw[0][0];
}
}
left_hotas1_value = left_hotas1_value / 10;
left_hotas2_value = left_hotas2_value / 10;
right_hotas1_value = right_hotas1_value / 10;
right_hotas2_value = right_hotas2_value / 10;
left_hotas1_adc_value[i] = left_hotas1_value;
left_hotas2_adc_value[i] = left_hotas2_value;
right_hotas1_adc_value[i] = right_hotas1_value;
right_hotas2_adc_value[i] = right_hotas2_value;
}
for (int i = 0; i < ADC_MEAS_WINDOW_SIZE; i++) {
rocker_value[0] += left_hotas1_adc_value[i];
rocker_value[1] += left_hotas2_adc_value[i];
rocker_value[2] += right_hotas1_adc_value[i];
rocker_value[3] += right_hotas2_adc_value[i];
}
rocker_value[0] = rocker_value[0] / ADC_MEAS_WINDOW_SIZE;
rocker_value[1] = rocker_value[1] / ADC_MEAS_WINDOW_SIZE;
rocker_value[2] = rocker_value[2] / ADC_MEAS_WINDOW_SIZE;
rocker_value[3] = rocker_value[3] / ADC_MEAS_WINDOW_SIZE;
}
void get_rocker_adc_value_in_rc_mode(uint16_t rocker_value[4], uint8_t meas_count, float filter_coef)
{
float left_hotas1_filtered_value = (float)rocker_value[0];
float left_hotas2_filtered_value = (float)rocker_value[1];
float right_hotas1_filtered_value = (float)rocker_value[2];
float right_hotas2_filtered_value = (float)rocker_value[3];
float left_hotas1_value = 0.0F;
float left_hotas2_value = 0.0F;
float right_hotas1_value = 0.0F;
float right_hotas2_value = 0.0F;
for (int i = 0; i < meas_count; i++) {
adc_oneshot_read(game_mode_adc_handle, LEFT_HOTAS1_ADC_CHAN, &g_left_hotas1_adc_raw[0][0]);
adc_oneshot_read(game_mode_adc_handle, LEFT_HOTAS2_ADC_CHAN, &g_left_hotas2_adc_raw[0][0]);
adc_oneshot_read(game_mode_adc_handle, RIGHT_HOTAS1_ADC_CHAN, &g_right_hotas1_adc_raw[0][0]);
adc_oneshot_read(game_mode_adc_handle, RIGHT_HOTAS2_ADC_CHAN, &g_right_hotas2_adc_raw[0][0]);
if (do_left_hotas1_adc_chan && do_left_hotas2_adc_chan && do_right_hotas1_adc_chan && do_right_hotas2_adc_chan) {
left_hotas1_value += g_left_hotas1_adc_raw[0][0] / (meas_count * 1.0);
left_hotas2_value += g_left_hotas2_adc_raw[0][0] / (meas_count * 1.0);
right_hotas1_value += g_right_hotas1_adc_raw[0][0] / (meas_count * 1.0);
right_hotas2_value += g_right_hotas2_adc_raw[0][0] / (meas_count * 1.0);
}
}
left_hotas1_filtered_value = left_hotas1_filtered_value * filter_coef + (1 - filter_coef) * left_hotas1_value;
left_hotas2_filtered_value = left_hotas2_filtered_value * filter_coef + (1 - filter_coef) * left_hotas2_value;
right_hotas1_filtered_value = right_hotas1_filtered_value * filter_coef + (1 - filter_coef) * right_hotas1_value;
right_hotas2_filtered_value = right_hotas2_filtered_value * filter_coef + (1 - filter_coef) * right_hotas2_value;
rocker_value[0] = (int)left_hotas1_filtered_value;
rocker_value[1] = (int)left_hotas2_filtered_value;
rocker_value[2] = (int)right_hotas1_filtered_value;
rocker_value[3] = (int)right_hotas2_filtered_value;
}
@@ -21,9 +21,11 @@ extern "C" {
#define RIGHT_HOTAS2_ADC_CHAN ADC_CHANNEL_3
#define EXAMPLE_ADC_ATTEN 3
#define ADC_MEAS_WINDOW_SIZE 10
esp_err_t rocker_adc_init(void);
void get_rocker_adc_value(uint16_t rocker_value[4]);
void get_rocker_adc_value_in_game_mode(uint16_t rocker_value[4]);
void get_rocker_adc_value_in_rc_mode(uint16_t rocker_value[4], uint8_t meas_count, float filter_coef);
#ifdef __cplusplus
}
@@ -139,6 +139,16 @@ static void game_pad_app_task(void *pvParameters)
}
}
if (1 == read_rocker_value_from_flash("hid_mode")) {
g_hid_mode = 1;
lv_obj_set_x(ui_hidModeSelectBtnPart, 22);
lv_label_set_text(ui_hidModeSelectLab, "BLE");
} else {
g_hid_mode = 0;
lv_obj_set_x(ui_hidModeSelectBtnPart, -22);
lv_label_set_text(ui_hidModeSelectLab, "USB");
}
box_rc_button_init();
if ( !(ROCKER_ADC_INIT_STATE & xEventGroupGetBits(g_init_event_grp))) {
@@ -170,7 +180,7 @@ static void game_pad_app_task(void *pvParameters)
while (1) {
while (1 == g_rocker_calibration_state) {
uint16_t rocker_adc_value[4] = {0};
get_rocker_adc_value(rocker_adc_value);
get_rocker_adc_value_in_game_mode(rocker_adc_value);
bsp_display_lock(0);
if (rocker_adc_value[0] >= left_rocker_x_adc_value[1]) {
@@ -281,10 +291,10 @@ static void rc_app_task(void *pvParameters)
right_rocker_y_adc_value[2] = read_rocker_value_from_flash("right_y_max");
}
uint16_t rocker_adc_value[4] = {0};
while (1) {
while (1 == g_rocker_calibration_state) {
uint16_t rocker_adc_value[4] = {0};
get_rocker_adc_value(rocker_adc_value);
get_rocker_adc_value_in_rc_mode(rocker_adc_value, 10, 0.6);
if (rocker_adc_value[0] >= left_rocker_x_adc_value[1]) {
rocker_x1 = (int)(((rocker_adc_value[0] - left_rocker_x_adc_value[1] * 1.0) / ((left_rocker_x_adc_value[2] - left_rocker_x_adc_value[1]) * 1.0)) * RC_ROCKET_RANGE);
@@ -407,19 +417,18 @@ void app_ui_event_rocker_calibration(lv_event_t *e)
right_rocker_x_adc_value[1] = 0;
right_rocker_y_adc_value[1] = 0;
for (int i = 0; i < 5; i++) {
get_rocker_adc_value(rocker_adc_value);
for (int i = 0; i < 10; i++) {
get_rocker_adc_value_in_game_mode(rocker_adc_value);
left_rocker_x_adc_value[1] += rocker_adc_value[0];
left_rocker_y_adc_value[1] += rocker_adc_value[1];
right_rocker_x_adc_value[1] += rocker_adc_value[2];
right_rocker_y_adc_value[1] += rocker_adc_value[3];
printf("%d, %d, %d, %d\n", rocker_adc_value[0], rocker_adc_value[1], rocker_adc_value[2], rocker_adc_value[3]);
vTaskDelay(pdMS_TO_TICKS(10));
}
left_rocker_x_adc_value[1] = left_rocker_x_adc_value[1] / 5;
left_rocker_y_adc_value[1] = left_rocker_y_adc_value[1] / 5;
right_rocker_x_adc_value[1] = right_rocker_x_adc_value[1] / 5;
right_rocker_y_adc_value[1] = right_rocker_y_adc_value[1] / 5;
left_rocker_x_adc_value[1] = left_rocker_x_adc_value[1] / 10.0;
left_rocker_y_adc_value[1] = left_rocker_y_adc_value[1] / 10.0;
right_rocker_x_adc_value[1] = right_rocker_x_adc_value[1] / 10.0;
right_rocker_y_adc_value[1] = right_rocker_y_adc_value[1] / 10.0;
printf("left x-mid: %d, left y-mid: %d, right x-mid: %d, right y-mid: %d\n", left_rocker_x_adc_value[1], left_rocker_y_adc_value[1],
right_rocker_x_adc_value[1], right_rocker_y_adc_value[1]);
sprintf(rocker_value_str, "%d", left_rocker_x_adc_value[1]);
@@ -440,7 +449,7 @@ void app_ui_event_rocker_calibration(lv_event_t *e)
lv_refr_now(NULL);
// Wait for the rocker to push into position
while (rocker_adc_value[0] > left_rocker_x_adc_value[1] - 600) {
get_rocker_adc_value(rocker_adc_value);
get_rocker_adc_value_in_game_mode(rocker_adc_value);
lv_obj_set_x(ui_leftRockerCalibrateBtn, -18);
lv_refr_now(NULL);
vTaskDelay(pdMS_TO_TICKS(10));
@@ -450,7 +459,7 @@ void app_ui_event_rocker_calibration(lv_event_t *e)
left_rocker_x_adc_value[0] = 0;
// Update the left rocker X axis minimum
for (int i = 0; i < 5; i++) {
get_rocker_adc_value(rocker_adc_value);
get_rocker_adc_value_in_game_mode(rocker_adc_value);
left_rocker_x_adc_value[0] += rocker_adc_value[0];
vTaskDelay(pdMS_TO_TICKS(10));
}
@@ -470,7 +479,7 @@ void app_ui_event_rocker_calibration(lv_event_t *e)
lv_refr_now(NULL);
// Wait for the rocker to push into position
while (rocker_adc_value[0] < left_rocker_x_adc_value[1] + 600) {
get_rocker_adc_value(rocker_adc_value);
get_rocker_adc_value_in_game_mode(rocker_adc_value);
lv_obj_set_x(ui_leftRockerCalibrateBtn, 18);
lv_refr_now(NULL);
vTaskDelay(pdMS_TO_TICKS(10));
@@ -479,7 +488,7 @@ void app_ui_event_rocker_calibration(lv_event_t *e)
left_rocker_x_adc_value[2] = 0;
// Update the left rocker X axis maximum
for (int i = 0; i < 5; i++) {
get_rocker_adc_value(rocker_adc_value);
get_rocker_adc_value_in_game_mode(rocker_adc_value);
left_rocker_x_adc_value[2] += rocker_adc_value[0];
vTaskDelay(pdMS_TO_TICKS(10));
}
@@ -500,7 +509,7 @@ void app_ui_event_rocker_calibration(lv_event_t *e)
lv_refr_now(NULL);
// Wait for the rocker to push into position
while (rocker_adc_value[1] < left_rocker_y_adc_value[1] + 600) {
get_rocker_adc_value(rocker_adc_value);
get_rocker_adc_value_in_game_mode(rocker_adc_value);
lv_obj_set_y(ui_leftRockerCalibrateBtn, -18);
lv_refr_now(NULL);
vTaskDelay(pdMS_TO_TICKS(10));
@@ -509,7 +518,7 @@ void app_ui_event_rocker_calibration(lv_event_t *e)
left_rocker_y_adc_value[2] = 0;
// Update the left rocker Y axis maximum
for (int i = 0; i < 5; i++) {
get_rocker_adc_value(rocker_adc_value);
get_rocker_adc_value_in_game_mode(rocker_adc_value);
left_rocker_y_adc_value[2] += rocker_adc_value[1];
vTaskDelay(pdMS_TO_TICKS(10));
}
@@ -527,7 +536,7 @@ void app_ui_event_rocker_calibration(lv_event_t *e)
lv_refr_now(NULL);
// Wait for the rocker to push into position
while (rocker_adc_value[1] > left_rocker_y_adc_value[1] - 600) {
get_rocker_adc_value(rocker_adc_value);
get_rocker_adc_value_in_game_mode(rocker_adc_value);
lv_obj_set_y(ui_leftRockerCalibrateBtn, 18);
lv_refr_now(NULL);
vTaskDelay(pdMS_TO_TICKS(10));
@@ -536,7 +545,7 @@ void app_ui_event_rocker_calibration(lv_event_t *e)
left_rocker_y_adc_value[0] = 0;
// Update the left rocker Y axis minimum
for (int i = 0; i < 5; i++) {
get_rocker_adc_value(rocker_adc_value);
get_rocker_adc_value_in_game_mode(rocker_adc_value);
left_rocker_y_adc_value[0] += rocker_adc_value[1];
vTaskDelay(pdMS_TO_TICKS(10));
}
@@ -554,7 +563,7 @@ void app_ui_event_rocker_calibration(lv_event_t *e)
lv_refr_now(NULL);
// Wait for the rocker to push into position
while (rocker_adc_value[2] > right_rocker_x_adc_value[1] - 600) {
get_rocker_adc_value(rocker_adc_value);
get_rocker_adc_value_in_game_mode(rocker_adc_value);
lv_obj_set_x(ui_rightRockerCalibrateBtn, -18);
lv_refr_now(NULL);
vTaskDelay(pdMS_TO_TICKS(10));
@@ -563,7 +572,7 @@ void app_ui_event_rocker_calibration(lv_event_t *e)
right_rocker_x_adc_value[0] = 0;
// Update the right rocker X axis minimum
for (int i = 0; i < 5; i++) {
get_rocker_adc_value(rocker_adc_value);
get_rocker_adc_value_in_game_mode(rocker_adc_value);
right_rocker_x_adc_value[0] += rocker_adc_value[2];
vTaskDelay(pdMS_TO_TICKS(10));
}
@@ -582,7 +591,7 @@ void app_ui_event_rocker_calibration(lv_event_t *e)
lv_refr_now(NULL);
// Wait for the rocker to push into position
while (rocker_adc_value[2] < right_rocker_x_adc_value[1] + 600) {
get_rocker_adc_value(rocker_adc_value);
get_rocker_adc_value_in_game_mode(rocker_adc_value);
lv_obj_set_x(ui_rightRockerCalibrateBtn, 18);
lv_refr_now(NULL);
vTaskDelay(pdMS_TO_TICKS(10));
@@ -591,7 +600,7 @@ void app_ui_event_rocker_calibration(lv_event_t *e)
right_rocker_x_adc_value[2] = 0;
// Update the right rocker X axis maximum
for (int i = 0; i < 5; i++) {
get_rocker_adc_value(rocker_adc_value);
get_rocker_adc_value_in_game_mode(rocker_adc_value);
right_rocker_x_adc_value[2] += rocker_adc_value[2];
vTaskDelay(pdMS_TO_TICKS(10));
}
@@ -611,7 +620,7 @@ void app_ui_event_rocker_calibration(lv_event_t *e)
lv_refr_now(NULL);
// Wait for the rocker to push into position
while (rocker_adc_value[3] < right_rocker_y_adc_value[1] + 600) {
get_rocker_adc_value(rocker_adc_value);
get_rocker_adc_value_in_game_mode(rocker_adc_value);
lv_obj_set_y(ui_rightRockerCalibrateBtn, -18);
lv_refr_now(NULL);
vTaskDelay(pdMS_TO_TICKS(10));
@@ -620,7 +629,7 @@ void app_ui_event_rocker_calibration(lv_event_t *e)
right_rocker_y_adc_value[2] = 0;
// Update the right rocker Y axis maximum
for (int i = 0; i < 5; i++) {
get_rocker_adc_value(rocker_adc_value);
get_rocker_adc_value_in_game_mode(rocker_adc_value);
right_rocker_y_adc_value[2] += rocker_adc_value[3];
vTaskDelay(pdMS_TO_TICKS(10));
}
@@ -638,7 +647,7 @@ void app_ui_event_rocker_calibration(lv_event_t *e)
lv_refr_now(NULL);
// Wait for the rocker to push into position
while (rocker_adc_value[3] > right_rocker_y_adc_value[1] - 600) {
get_rocker_adc_value(rocker_adc_value);
get_rocker_adc_value_in_game_mode(rocker_adc_value);
lv_obj_set_y(ui_rightRockerCalibrateBtn, 18);
lv_refr_now(NULL);
vTaskDelay(pdMS_TO_TICKS(10));
@@ -647,7 +656,7 @@ void app_ui_event_rocker_calibration(lv_event_t *e)
right_rocker_y_adc_value[0] = 0;
// Update the right rocker Y axis minimum
for (int i = 0; i < 5; i++) {
get_rocker_adc_value(rocker_adc_value);
get_rocker_adc_value_in_game_mode(rocker_adc_value);
right_rocker_y_adc_value[0] += rocker_adc_value[3];
vTaskDelay(pdMS_TO_TICKS(10));
}
@@ -682,10 +691,12 @@ void app_ui_event_hid_mode_select(lv_event_t *e)
ESP_LOGI(GAME_PAD_APP_TAG, "BLE HID mode.");
lv_obj_set_x(ui_hidModeSelectBtnPart, 22);
lv_label_set_text(ui_hidModeSelectLab, "BLE");
flash_write_state("hid_mode", "1");
} else {
ESP_LOGI(GAME_PAD_APP_TAG, "USB HID mode.");
lv_obj_set_x(ui_hidModeSelectBtnPart, -22);
lv_label_set_text(ui_hidModeSelectLab, "USB");
flash_write_state("hid_mode", "0");
}
}
@@ -1,6 +1,9 @@
targets:
- esp32s3
dependencies:
lvgl/lvgl:
version: "^8"
public: true
espressif/esp-now: "^2.4.0"
espressif/esp-box-3: "^1.1.2"
espressif/button: "^3.1.3"