mirror of
https://github.com/78/xiaozhi-esp32.git
synced 2026-07-01 01:44:35 +08:00
* Enable WebSocket control server for electron-bot * Add servo control features to ElectronBot - Introduced new actions for servo movement and sequences, including ACTION_SERVO_MOVE and ACTION_SERVO_SEQUENCE. - Implemented methods for clamping servo positions and applying oscillation effects. - Added GetServoPositions method to retrieve current servo angles. - Enhanced README.md with detailed AI command examples and servo capabilities. These changes improve the flexibility and control of the ElectronBot's movements, allowing for more complex actions and better integration with AI functionalities. * Refactor servo control in ElectronBot - Removed unnecessary home action logic during servo sequences to improve action fluidity. - Updated README.md to clarify the action parameters for hand movements, specifically the amplitude for flapping actions. - Introduced clamping functions for servo angles and amplitudes to ensure safe operation within defined limits. These changes enhance the control and safety of the ElectronBot's servo movements, allowing for more precise and natural actions.
148 lines
5.3 KiB
C++
148 lines
5.3 KiB
C++
#include <driver/i2c_master.h>
|
|
#include <driver/spi_common.h>
|
|
#include <esp_lcd_gc9a01.h>
|
|
#include <esp_lcd_panel_io.h>
|
|
#include <esp_lcd_panel_ops.h>
|
|
#include <esp_lcd_panel_vendor.h>
|
|
#include <esp_log.h>
|
|
|
|
#include "application.h"
|
|
#include "codecs/no_audio_codec.h"
|
|
#include "button.h"
|
|
#include "config.h"
|
|
#include "display/lcd_display.h"
|
|
#include "driver/spi_master.h"
|
|
#include "electron_emoji_display.h"
|
|
#include "movements.h"
|
|
#include "power_manager.h"
|
|
#include "system_reset.h"
|
|
#include "websocket_control_server.h"
|
|
#include "wifi_board.h"
|
|
|
|
#define TAG "ElectronBot"
|
|
|
|
// 控制器初始化函数声明
|
|
void InitializeElectronBotController();
|
|
|
|
class ElectronBot : public WifiBoard {
|
|
private:
|
|
Display* display_;
|
|
PowerManager* power_manager_;
|
|
Button boot_button_;
|
|
WebSocketControlServer* ws_control_server_;
|
|
|
|
void InitializePowerManager() {
|
|
power_manager_ =
|
|
new PowerManager(POWER_CHARGE_DETECT_PIN, POWER_ADC_UNIT, POWER_ADC_CHANNEL);
|
|
}
|
|
|
|
void InitializeSpi() {
|
|
ESP_LOGI(TAG, "Initialize SPI bus");
|
|
spi_bus_config_t buscfg =
|
|
GC9A01_PANEL_BUS_SPI_CONFIG(DISPLAY_SPI_SCLK_PIN, DISPLAY_SPI_MOSI_PIN,
|
|
DISPLAY_WIDTH * DISPLAY_HEIGHT * sizeof(uint16_t));
|
|
ESP_ERROR_CHECK(spi_bus_initialize(SPI3_HOST, &buscfg, SPI_DMA_CH_AUTO));
|
|
}
|
|
|
|
// GC9A01初始化
|
|
void InitializeGc9a01Display() {
|
|
ESP_LOGI(TAG, "Init GC9A01 display");
|
|
|
|
ESP_LOGI(TAG, "Install panel IO");
|
|
esp_lcd_panel_io_handle_t io_handle = NULL;
|
|
esp_lcd_panel_io_spi_config_t io_config =
|
|
GC9A01_PANEL_IO_SPI_CONFIG(DISPLAY_SPI_CS_PIN, DISPLAY_SPI_DC_PIN, NULL, NULL);
|
|
io_config.pclk_hz = DISPLAY_SPI_SCLK_HZ;
|
|
ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi(SPI3_HOST, &io_config, &io_handle));
|
|
|
|
ESP_LOGI(TAG, "Install GC9A01 panel driver");
|
|
esp_lcd_panel_handle_t panel_handle = NULL;
|
|
esp_lcd_panel_dev_config_t panel_config = {};
|
|
panel_config.reset_gpio_num = DISPLAY_SPI_RESET_PIN; // Set to -1 if not use
|
|
panel_config.rgb_endian = LCD_RGB_ENDIAN_BGR; // LCD_RGB_ENDIAN_RGB;
|
|
panel_config.bits_per_pixel = 16; // Implemented by LCD command `3Ah` (16/18)
|
|
|
|
ESP_ERROR_CHECK(esp_lcd_new_panel_gc9a01(io_handle, &panel_config, &panel_handle));
|
|
ESP_ERROR_CHECK(esp_lcd_panel_reset(panel_handle));
|
|
ESP_ERROR_CHECK(esp_lcd_panel_init(panel_handle));
|
|
ESP_ERROR_CHECK(esp_lcd_panel_invert_color(panel_handle, true));
|
|
ESP_ERROR_CHECK(esp_lcd_panel_mirror(panel_handle, true, false));
|
|
ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel_handle, true));
|
|
|
|
display_ = new ElectronEmojiDisplay(io_handle, panel_handle, DISPLAY_WIDTH, DISPLAY_HEIGHT,
|
|
DISPLAY_OFFSET_X, DISPLAY_OFFSET_Y, DISPLAY_MIRROR_X,
|
|
DISPLAY_MIRROR_Y, DISPLAY_SWAP_XY);
|
|
}
|
|
|
|
void InitializeButtons() {
|
|
boot_button_.OnClick([this]() {
|
|
auto& app = Application::GetInstance();
|
|
if (app.GetDeviceState() == kDeviceStateStarting) {
|
|
EnterWifiConfigMode();
|
|
return;
|
|
}
|
|
app.ToggleChatState();
|
|
});
|
|
}
|
|
|
|
void InitializeController() { InitializeElectronBotController(); }
|
|
|
|
void InitializeWebSocketControlServer() {
|
|
ws_control_server_ = new WebSocketControlServer();
|
|
if (!ws_control_server_->Start(8080)) {
|
|
delete ws_control_server_;
|
|
ws_control_server_ = nullptr;
|
|
return;
|
|
}
|
|
|
|
Application::GetInstance().RegisterMcpBroadcastCallback([this](const std::string& payload) {
|
|
if (ws_control_server_) {
|
|
ws_control_server_->BroadcastMessage(payload);
|
|
}
|
|
});
|
|
}
|
|
|
|
void StartNetwork() override {
|
|
WifiBoard::StartNetwork();
|
|
vTaskDelay(pdMS_TO_TICKS(1000));
|
|
|
|
InitializeWebSocketControlServer();
|
|
}
|
|
|
|
public:
|
|
ElectronBot() : boot_button_(BOOT_BUTTON_GPIO), ws_control_server_(nullptr) {
|
|
InitializeSpi();
|
|
InitializeGc9a01Display();
|
|
InitializeButtons();
|
|
InitializePowerManager();
|
|
InitializeController();
|
|
|
|
if (DISPLAY_BACKLIGHT_PIN != GPIO_NUM_NC) {
|
|
GetBacklight()->RestoreBrightness();
|
|
}
|
|
}
|
|
|
|
virtual AudioCodec* GetAudioCodec() override {
|
|
static NoAudioCodecSimplex audio_codec(AUDIO_INPUT_SAMPLE_RATE, AUDIO_OUTPUT_SAMPLE_RATE,
|
|
AUDIO_I2S_SPK_GPIO_BCLK, AUDIO_I2S_SPK_GPIO_LRCK,
|
|
AUDIO_I2S_SPK_GPIO_DOUT, AUDIO_I2S_MIC_GPIO_SCK,
|
|
AUDIO_I2S_MIC_GPIO_WS, AUDIO_I2S_MIC_GPIO_DIN);
|
|
return &audio_codec;
|
|
}
|
|
|
|
virtual Display* GetDisplay() override { return display_; }
|
|
|
|
virtual Backlight* GetBacklight() override {
|
|
static PwmBacklight backlight(DISPLAY_BACKLIGHT_PIN, DISPLAY_BACKLIGHT_OUTPUT_INVERT);
|
|
return &backlight;
|
|
}
|
|
virtual bool GetBatteryLevel(int& level, bool& charging, bool& discharging) override {
|
|
charging = power_manager_->IsCharging();
|
|
discharging = !charging;
|
|
level = power_manager_->GetBatteryLevel();
|
|
return true;
|
|
}
|
|
};
|
|
|
|
DECLARE_BOARD(ElectronBot);
|