From 6b3993bd034005a081d740dec848384263030624 Mon Sep 17 00:00:00 2001 From: Liang Hao Date: Thu, 6 Jun 2024 16:34:25 +0800 Subject: [PATCH] feat(esp_joystick): eliminate joystick ADC jitter Add power-off memory function for HID mode selection Close AEG-1578 --- .../main/app/app_ble_hid.c | 5 +- .../joystick_controller/main/app/app_rocker.c | 88 ++++++++++++++++--- .../joystick_controller/main/app/app_rocker.h | 4 +- .../joystick_controller/main/app_ui_event.c | 63 +++++++------ .../main/idf_component.yml | 3 + 5 files changed, 125 insertions(+), 38 deletions(-) diff --git a/examples/esp_joystick/joystick_controller/main/app/app_ble_hid.c b/examples/esp_joystick/joystick_controller/main/app/app_ble_hid.c index a89bd243..c9f634e4 100644 --- a/examples/esp_joystick/joystick_controller/main/app/app_ble_hid.c +++ b/examples/esp_joystick/joystick_controller/main/app/app_ble_hid.c @@ -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; } diff --git a/examples/esp_joystick/joystick_controller/main/app/app_rocker.c b/examples/esp_joystick/joystick_controller/main/app/app_rocker.c index 8600d413..bb58193e 100644 --- a/examples/esp_joystick/joystick_controller/main/app/app_rocker.c +++ b/examples/esp_joystick/joystick_controller/main/app/app_rocker.c @@ -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; } diff --git a/examples/esp_joystick/joystick_controller/main/app/app_rocker.h b/examples/esp_joystick/joystick_controller/main/app/app_rocker.h index 4cd6fb72..04ad11f2 100644 --- a/examples/esp_joystick/joystick_controller/main/app/app_rocker.h +++ b/examples/esp_joystick/joystick_controller/main/app/app_rocker.h @@ -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 } diff --git a/examples/esp_joystick/joystick_controller/main/app_ui_event.c b/examples/esp_joystick/joystick_controller/main/app_ui_event.c index 6ab6fc74..931f3b0c 100644 --- a/examples/esp_joystick/joystick_controller/main/app_ui_event.c +++ b/examples/esp_joystick/joystick_controller/main/app_ui_event.c @@ -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"); } } diff --git a/examples/esp_joystick/joystick_controller/main/idf_component.yml b/examples/esp_joystick/joystick_controller/main/idf_component.yml index da51e062..d4a01502 100644 --- a/examples/esp_joystick/joystick_controller/main/idf_component.yml +++ b/examples/esp_joystick/joystick_controller/main/idf_component.yml @@ -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"