esp_hi.cc 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418
  1. #include "wifi_board.h"
  2. #include "adc_pdm_audio_codec.h"
  3. #include "application.h"
  4. #include "button.h"
  5. #include "config.h"
  6. #include "mcp_server.h"
  7. #include <wifi_station.h>
  8. #include <esp_log.h>
  9. #include <driver/i2c_master.h>
  10. #include <driver/spi_common.h>
  11. #include <esp_wifi.h>
  12. #include <esp_event.h>
  13. #include "display/lcd_display.h"
  14. #include <esp_lcd_panel_vendor.h>
  15. #include <esp_lcd_panel_io.h>
  16. #include <esp_lcd_panel_ops.h>
  17. #include "esp_lcd_ili9341.h"
  18. #include "assets/lang_config.h"
  19. #include "anim_player.h"
  20. #include "emoji_display.h"
  21. #include "servo_dog_ctrl.h"
  22. #include "led_strip.h"
  23. #include "driver/rmt_tx.h"
  24. #include "sdkconfig.h"
  25. #ifdef CONFIG_ESP_HI_WEB_CONTROL_ENABLED
  26. #include "esp_hi_web_control.h"
  27. #endif //CONFIG_ESP_HI_WEB_CONTROL_ENABLED
  28. #define TAG "ESP_HI"
  29. static const ili9341_lcd_init_cmd_t vendor_specific_init[] = {
  30. {0x11, NULL, 0, 120}, // Sleep out, Delay 120ms
  31. {0xB1, (uint8_t []){0x05, 0x3A, 0x3A}, 3, 0},
  32. {0xB2, (uint8_t []){0x05, 0x3A, 0x3A}, 3, 0},
  33. {0xB3, (uint8_t []){0x05, 0x3A, 0x3A, 0x05, 0x3A, 0x3A}, 6, 0},
  34. {0xB4, (uint8_t []){0x03}, 1, 0}, // Dot inversion
  35. {0xC0, (uint8_t []){0x44, 0x04, 0x04}, 3, 0},
  36. {0xC1, (uint8_t []){0xC0}, 1, 0},
  37. {0xC2, (uint8_t []){0x0D, 0x00}, 2, 0},
  38. {0xC3, (uint8_t []){0x8D, 0x6A}, 2, 0},
  39. {0xC4, (uint8_t []){0x8D, 0xEE}, 2, 0},
  40. {0xC5, (uint8_t []){0x08}, 1, 0},
  41. {0xE0, (uint8_t []){0x0F, 0x10, 0x03, 0x03, 0x07, 0x02, 0x00, 0x02, 0x07, 0x0C, 0x13, 0x38, 0x0A, 0x0E, 0x03, 0x10}, 16, 0},
  42. {0xE1, (uint8_t []){0x10, 0x0B, 0x04, 0x04, 0x10, 0x03, 0x00, 0x03, 0x03, 0x09, 0x17, 0x33, 0x0B, 0x0C, 0x06, 0x10}, 16, 0},
  43. {0x35, (uint8_t []){0x00}, 1, 0},
  44. {0x3A, (uint8_t []){0x05}, 1, 0},
  45. {0x36, (uint8_t []){0xC8}, 1, 0},
  46. {0x29, NULL, 0, 0}, // Display on
  47. {0x2C, NULL, 0, 0}, // Memory write
  48. };
  49. static const led_strip_config_t bsp_strip_config = {
  50. .strip_gpio_num = GPIO_NUM_8,
  51. .max_leds = 4,
  52. .led_model = LED_MODEL_WS2812,
  53. .flags = {
  54. .invert_out = false
  55. }
  56. };
  57. static const led_strip_rmt_config_t bsp_rmt_config = {
  58. .clk_src = RMT_CLK_SRC_DEFAULT,
  59. .resolution_hz = 10 * 1000 * 1000,
  60. .flags = {
  61. .with_dma = false
  62. }
  63. };
  64. class EspHi : public WifiBoard {
  65. private:
  66. Button boot_button_;
  67. Button audio_wake_button_;
  68. Button move_wake_button_;
  69. anim::EmojiWidget* display_ = nullptr;
  70. bool web_server_initialized_ = false;
  71. led_strip_handle_t led_strip_;
  72. bool led_on_ = false;
  73. #ifdef CONFIG_ESP_HI_WEB_CONTROL_ENABLED
  74. static void wifi_event_handler(void* arg, esp_event_base_t event_base,
  75. int32_t event_id, void* event_data)
  76. {
  77. if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_CONNECTED) {
  78. xTaskCreate(
  79. [](void* arg) {
  80. EspHi* instance = static_cast<EspHi*>(arg);
  81. vTaskDelay(5000 / portTICK_PERIOD_MS);
  82. if (!instance->web_server_initialized_) {
  83. ESP_LOGI(TAG, "WiFi connected, init web control server");
  84. esp_err_t err = esp_hi_web_control_server_init();
  85. if (err != ESP_OK) {
  86. ESP_LOGE(TAG, "Failed to initialize web control server: %d", err);
  87. } else {
  88. ESP_LOGI(TAG, "Web control server initialized");
  89. instance->web_server_initialized_ = true;
  90. }
  91. }
  92. vTaskDelete(NULL);
  93. },
  94. "web_server_init",
  95. 1024 * 10, arg, 5, nullptr);
  96. }
  97. }
  98. #endif //CONFIG_ESP_HI_WEB_CONTROL_ENABLED
  99. void HandleMoveWakePressDown(int64_t current_time, int64_t &last_trigger_time, int &gesture_state)
  100. {
  101. int64_t interval = last_trigger_time == 0 ? 0 : current_time - last_trigger_time;
  102. last_trigger_time = current_time;
  103. if (interval > 1000) {
  104. gesture_state = 0;
  105. } else {
  106. switch (gesture_state) {
  107. case 0:
  108. break;
  109. case 1:
  110. if (interval > 300) {
  111. gesture_state = 2;
  112. }
  113. break;
  114. case 2:
  115. if (interval > 100) {
  116. gesture_state = 0;
  117. }
  118. break;
  119. }
  120. }
  121. }
  122. void HandleMoveWakePressUp(int64_t current_time, int64_t &last_trigger_time, int &gesture_state)
  123. {
  124. int64_t interval = current_time - last_trigger_time;
  125. if (interval > 1000) {
  126. gesture_state = 0;
  127. } else {
  128. switch (gesture_state) {
  129. case 0:
  130. if (interval > 300) {
  131. gesture_state = 1;
  132. }
  133. break;
  134. case 1:
  135. break;
  136. case 2:
  137. if (interval < 100) {
  138. ESP_LOGI(TAG, "gesture detected");
  139. gesture_state = 0;
  140. auto &app = Application::GetInstance();
  141. app.ToggleChatState();
  142. }
  143. break;
  144. }
  145. }
  146. }
  147. void InitializeButtons()
  148. {
  149. static int64_t last_trigger_time = 0;
  150. static int gesture_state = 0; // 0: init, 1: wait second long interval, 2: wait oscillation
  151. boot_button_.OnClick([this]() {
  152. auto &app = Application::GetInstance();
  153. if (app.GetDeviceState() == kDeviceStateStarting && !WifiStation::GetInstance().IsConnected()) {
  154. ResetWifiConfiguration();
  155. }
  156. app.ToggleChatState();
  157. });
  158. audio_wake_button_.OnPressDown([this]() {
  159. });
  160. audio_wake_button_.OnPressUp([this]() {
  161. });
  162. move_wake_button_.OnPressDown([this]() {
  163. int64_t current_time = esp_timer_get_time() / 1000;
  164. HandleMoveWakePressDown(current_time, last_trigger_time, gesture_state);
  165. });
  166. move_wake_button_.OnPressUp([this]() {
  167. int64_t current_time = esp_timer_get_time() / 1000;
  168. HandleMoveWakePressUp(current_time, last_trigger_time, gesture_state);
  169. });
  170. }
  171. void InitializeLed() {
  172. ESP_LOGI(TAG, "BLINK_GPIO setting %d", bsp_strip_config.strip_gpio_num);
  173. ESP_ERROR_CHECK(led_strip_new_rmt_device(&bsp_strip_config, &bsp_rmt_config, &led_strip_));
  174. led_strip_set_pixel(led_strip_, 0, 0x00, 0x00, 0x00);
  175. led_strip_set_pixel(led_strip_, 1, 0x00, 0x00, 0x00);
  176. led_strip_set_pixel(led_strip_, 2, 0x00, 0x00, 0x00);
  177. led_strip_set_pixel(led_strip_, 3, 0x00, 0x00, 0x00);
  178. led_strip_refresh(led_strip_);
  179. }
  180. esp_err_t SetLedColor(uint8_t r, uint8_t g, uint8_t b) {
  181. esp_err_t ret = ESP_OK;
  182. ret |= led_strip_set_pixel(led_strip_, 0, r, g, b);
  183. ret |= led_strip_set_pixel(led_strip_, 1, r, g, b);
  184. ret |= led_strip_set_pixel(led_strip_, 2, r, g, b);
  185. ret |= led_strip_set_pixel(led_strip_, 3, r, g, b);
  186. ret |= led_strip_refresh(led_strip_);
  187. return ret;
  188. }
  189. void InitializeIot()
  190. {
  191. ESP_LOGI(TAG, "Initialize Iot");
  192. InitializeLed();
  193. SetLedColor(0x00, 0x00, 0x00);
  194. #ifdef CONFIG_ESP_HI_WEB_CONTROL_ENABLED
  195. ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_STA_CONNECTED,
  196. &wifi_event_handler, this));
  197. #endif //CONFIG_ESP_HI_WEB_CONTROL_ENABLED
  198. }
  199. void InitializeSpi()
  200. {
  201. spi_bus_config_t buscfg = {};
  202. buscfg.mosi_io_num = DISPLAY_MOSI_PIN;
  203. buscfg.miso_io_num = GPIO_NUM_NC;
  204. buscfg.sclk_io_num = DISPLAY_CLK_PIN;
  205. buscfg.quadwp_io_num = GPIO_NUM_NC;
  206. buscfg.quadhd_io_num = GPIO_NUM_NC;
  207. buscfg.max_transfer_sz = DISPLAY_WIDTH * 10 * sizeof(uint16_t);
  208. ESP_ERROR_CHECK(spi_bus_initialize(SPI2_HOST, &buscfg, SPI_DMA_CH_AUTO));
  209. }
  210. void InitializeLcdDisplay()
  211. {
  212. esp_lcd_panel_io_handle_t panel_io = nullptr;
  213. esp_lcd_panel_handle_t panel = nullptr;
  214. // 液晶屏控制IO初始化
  215. ESP_LOGD(TAG, "Install panel IO");
  216. esp_lcd_panel_io_spi_config_t io_config = {};
  217. io_config.cs_gpio_num = DISPLAY_CS_PIN;
  218. io_config.dc_gpio_num = DISPLAY_DC_PIN;
  219. io_config.spi_mode = DISPLAY_SPI_MODE;
  220. io_config.pclk_hz = 40 * 1000 * 1000;
  221. io_config.trans_queue_depth = 10;
  222. io_config.lcd_cmd_bits = 8;
  223. io_config.lcd_param_bits = 8;
  224. ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi(SPI2_HOST, &io_config, &panel_io));
  225. // 初始化液晶屏驱动芯片
  226. ESP_LOGD(TAG, "Install LCD driver");
  227. const ili9341_vendor_config_t vendor_config = {
  228. .init_cmds = &vendor_specific_init[0],
  229. .init_cmds_size = sizeof(vendor_specific_init) / sizeof(ili9341_lcd_init_cmd_t),
  230. };
  231. esp_lcd_panel_dev_config_t panel_config = {};
  232. panel_config.reset_gpio_num = DISPLAY_RST_PIN;
  233. panel_config.rgb_ele_order = DISPLAY_RGB_ORDER;
  234. panel_config.bits_per_pixel = 16;
  235. panel_config.vendor_config = (void *) &vendor_config;
  236. ESP_ERROR_CHECK(esp_lcd_new_panel_ili9341(panel_io, &panel_config, &panel));
  237. esp_lcd_panel_reset(panel);
  238. esp_lcd_panel_init(panel);
  239. esp_lcd_panel_invert_color(panel, DISPLAY_INVERT_COLOR);
  240. esp_lcd_panel_invert_color(panel, false);
  241. esp_lcd_panel_set_gap(panel, 0, 24);
  242. esp_lcd_panel_mirror(panel, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y);
  243. esp_lcd_panel_swap_xy(panel, DISPLAY_SWAP_XY);
  244. ESP_LOGI(TAG, "LCD panel create success, %p", panel);
  245. esp_lcd_panel_disp_on_off(panel, true);
  246. ESP_LOGI(TAG, "Create emoji widget, panel: %p, panel_io: %p", panel, panel_io);
  247. display_ = new anim::EmojiWidget(panel, panel_io);
  248. servo_dog_ctrl_config_t config = {
  249. .fl_gpio_num = FL_GPIO_NUM,
  250. .fr_gpio_num = FR_GPIO_NUM,
  251. .bl_gpio_num = BL_GPIO_NUM,
  252. .br_gpio_num = BR_GPIO_NUM,
  253. };
  254. #if CONFIG_ESP_CONSOLE_NONE
  255. servo_dog_ctrl_init(&config);
  256. #endif
  257. }
  258. void InitializeTools()
  259. {
  260. auto& mcp_server = McpServer::GetInstance();
  261. // 基础动作控制
  262. mcp_server.AddTool("self.dog.basic_control", "机器人的基础动作。机器人可以做以下基础动作:\n"
  263. "forward: 向前移动\nbackward: 向后移动\nturn_left: 向左转\nturn_right: 向右转\nstop: 立即停止当前动作",
  264. PropertyList({
  265. Property("action", kPropertyTypeString),
  266. }), [this](const PropertyList& properties) -> ReturnValue {
  267. const std::string& action = properties["action"].value<std::string>();
  268. if (action == "forward") {
  269. servo_dog_ctrl_send(DOG_STATE_FORWARD, NULL);
  270. } else if (action == "backward") {
  271. servo_dog_ctrl_send(DOG_STATE_BACKWARD, NULL);
  272. } else if (action == "turn_left") {
  273. servo_dog_ctrl_send(DOG_STATE_TURN_LEFT, NULL);
  274. } else if (action == "turn_right") {
  275. servo_dog_ctrl_send(DOG_STATE_TURN_RIGHT, NULL);
  276. } else if (action == "stop") {
  277. servo_dog_ctrl_send(DOG_STATE_IDLE, NULL);
  278. } else {
  279. return false;
  280. }
  281. return true;
  282. });
  283. // 扩展动作控制
  284. mcp_server.AddTool("self.dog.advanced_control", "机器人的扩展动作。机器人可以做以下扩展动作:\n"
  285. "sway_back_forth: 前后摇摆\nlay_down: 趴下\nsway: 左右摇摆\nretract_legs: 收回腿部\n"
  286. "shake_hand: 握手\nshake_back_legs: 伸懒腰\njump_forward: 向前跳跃",
  287. PropertyList({
  288. Property("action", kPropertyTypeString),
  289. }), [this](const PropertyList& properties) -> ReturnValue {
  290. const std::string& action = properties["action"].value<std::string>();
  291. if (action == "sway_back_forth") {
  292. servo_dog_ctrl_send(DOG_STATE_SWAY_BACK_FORTH, NULL);
  293. } else if (action == "lay_down") {
  294. servo_dog_ctrl_send(DOG_STATE_LAY_DOWN, NULL);
  295. } else if (action == "sway") {
  296. dog_action_args_t args = {
  297. .repeat_count = 4,
  298. };
  299. servo_dog_ctrl_send(DOG_STATE_SWAY, &args);
  300. } else if (action == "retract_legs") {
  301. servo_dog_ctrl_send(DOG_STATE_RETRACT_LEGS, NULL);
  302. } else if (action == "shake_hand") {
  303. servo_dog_ctrl_send(DOG_STATE_SHAKE_HAND, NULL);
  304. } else if (action == "shake_back_legs") {
  305. servo_dog_ctrl_send(DOG_STATE_SHAKE_BACK_LEGS, NULL);
  306. } else if (action == "jump_forward") {
  307. servo_dog_ctrl_send(DOG_STATE_JUMP_FORWARD, NULL);
  308. } else {
  309. return false;
  310. }
  311. return true;
  312. });
  313. // 灯光控制
  314. mcp_server.AddTool("self.light.get_power", "获取灯是否打开", PropertyList(), [this](const PropertyList& properties) -> ReturnValue {
  315. return led_on_;
  316. });
  317. mcp_server.AddTool("self.light.turn_on", "打开灯", PropertyList(), [this](const PropertyList& properties) -> ReturnValue {
  318. SetLedColor(0xFF, 0xFF, 0xFF);
  319. led_on_ = true;
  320. return true;
  321. });
  322. mcp_server.AddTool("self.light.turn_off", "关闭灯", PropertyList(), [this](const PropertyList& properties) -> ReturnValue {
  323. SetLedColor(0x00, 0x00, 0x00);
  324. led_on_ = false;
  325. return true;
  326. });
  327. mcp_server.AddTool("self.light.set_rgb", "设置RGB颜色", PropertyList({
  328. Property("r", kPropertyTypeInteger, 0, 255),
  329. Property("g", kPropertyTypeInteger, 0, 255),
  330. Property("b", kPropertyTypeInteger, 0, 255)
  331. }), [this](const PropertyList& properties) -> ReturnValue {
  332. int r = properties["r"].value<int>();
  333. int g = properties["g"].value<int>();
  334. int b = properties["b"].value<int>();
  335. led_on_ = true;
  336. SetLedColor(r, g, b);
  337. return true;
  338. });
  339. }
  340. public:
  341. EspHi() : boot_button_(BOOT_BUTTON_GPIO),
  342. audio_wake_button_(AUDIO_WAKE_BUTTON_GPIO),
  343. move_wake_button_(MOVE_WAKE_BUTTON_GPIO)
  344. {
  345. InitializeButtons();
  346. InitializeIot();
  347. InitializeSpi();
  348. InitializeLcdDisplay();
  349. InitializeTools();
  350. }
  351. virtual AudioCodec* GetAudioCodec() override
  352. {
  353. static AdcPdmAudioCodec audio_codec(
  354. AUDIO_INPUT_SAMPLE_RATE,
  355. AUDIO_OUTPUT_SAMPLE_RATE,
  356. AUDIO_ADC_MIC_CHANNEL,
  357. AUDIO_PDM_SPEAK_P_GPIO,
  358. AUDIO_PDM_SPEAK_N_GPIO,
  359. AUDIO_PA_CTL_GPIO);
  360. return &audio_codec;
  361. }
  362. virtual Display* GetDisplay() override
  363. {
  364. return display_;
  365. }
  366. };
  367. DECLARE_BOARD(EspHi);