基于IDF5.5.1的小智2.0.5版本移植第三方S3开发板使用MCP进行语音步进电机精准控制
本文最后更新于289 天前,其中的信息可能已经过时,如有错误请发送邮件到cishaxiatian@gmail.com

本文章默认安装好VsCode的IDF的环境,如果没有安装好环境,可以看嘉立创的IDF安装环境 1. IDF环境安装 | 立创开发板技术文档中心

1.下载小智AI的源码

Release v2.0.5 · 78/xiaozhi-esp32

1

2.解压使用vscode的打开文件夹功能打开下载的小智文件夹

2.打开小智AI代码进行自定义配置

3.进入打开的工程文件夹,添加第三方(自己画的,或者是买的)开发板,这里是自己画的,新建文件夹 A-stepper-motor 以及三个文件

3

A_stepper_motor.cc

文件夹的名字和c++文件的名字可以随意,这里是A_stepper_motor

#include "wifi_board.h"
#include "codecs/no_audio_codec.h"
#include "display/oled_display.h"
#include "system_reset.h"
#include "application.h"
#include "button.h"
#include "config.h"
#include "mcp_server.h"
#include "lamp_controller.h"
#include "led/single_led.h"
#include "assets/lang_config.h"

#include <wifi_station.h>
#include <esp_log.h>
#include <driver/i2c_master.h>
#include <esp_lcd_panel_ops.h>
#include <esp_lcd_panel_vendor.h>

#ifdef SH1106
#include <esp_lcd_panel_sh1106.h>
#endif

#define TAG "A_stepper_motor"

class A_stepper_motor : public WifiBoard {
private:
    i2c_master_bus_handle_t display_i2c_bus_;
    esp_lcd_panel_io_handle_t panel_io_ = nullptr;
    esp_lcd_panel_handle_t panel_ = nullptr;
    Display* display_ = nullptr;
    Button boot_button_;
    Button touch_button_;
    Button volume_up_button_;
    Button volume_down_button_;

    void InitializeDisplayI2c() {
        i2c_master_bus_config_t bus_config = {
            .i2c_port = (i2c_port_t)0,
            .sda_io_num = DISPLAY_SDA_PIN,
            .scl_io_num = DISPLAY_SCL_PIN,
            .clk_source = I2C_CLK_SRC_DEFAULT,
            .glitch_ignore_cnt = 7,
            .intr_priority = 0,
            .trans_queue_depth = 0,
            .flags = {
                .enable_internal_pullup = 1,
            },
        };
        ESP_ERROR_CHECK(i2c_new_master_bus(&bus_config, &display_i2c_bus_));
    }

    void InitializeSsd1306Display() {
        // SSD1306 config
        esp_lcd_panel_io_i2c_config_t io_config = {
            .dev_addr = 0x3C,
            .on_color_trans_done = nullptr,
            .user_ctx = nullptr,
            .control_phase_bytes = 1,
            .dc_bit_offset = 6,
            .lcd_cmd_bits = 8,
            .lcd_param_bits = 8,
            .flags = {
                .dc_low_on_data = 0,
                .disable_control_phase = 0,
            },
            .scl_speed_hz = 400 * 1000,
        };

        ESP_ERROR_CHECK(esp_lcd_new_panel_io_i2c_v2(display_i2c_bus_, &io_config, &panel_io_));

        ESP_LOGI(TAG, "Install SSD1306 driver");
        esp_lcd_panel_dev_config_t panel_config = {};
        panel_config.reset_gpio_num = -1;
        panel_config.bits_per_pixel = 1;

        esp_lcd_panel_ssd1306_config_t ssd1306_config = {
            .height = static_cast
<uint8_t>(DISPLAY_HEIGHT),
        };
        panel_config.vendor_config = &ssd1306_config;

#ifdef SH1106
        ESP_ERROR_CHECK(esp_lcd_new_panel_sh1106(panel_io_, &panel_config, &panel_));
#else
        ESP_ERROR_CHECK(esp_lcd_new_panel_ssd1306(panel_io_, &panel_config, &panel_));
#endif
        ESP_LOGI(TAG, "SSD1306 driver installed");

        // Reset the display
        ESP_ERROR_CHECK(esp_lcd_panel_reset(panel_));
        if (esp_lcd_panel_init(panel_) != ESP_OK) {
            ESP_LOGE(TAG, "Failed to initialize display");
            display_ = new NoDisplay();
            return;
        }
        ESP_ERROR_CHECK(esp_lcd_panel_invert_color(panel_, false));

        // Set the display to on
        ESP_LOGI(TAG, "Turning display on");
        ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel_, true));

        display_ = new OledDisplay(panel_io_, panel_, DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y);
    }

    void InitializeButtons() {
        boot_button_.OnClick([this]() {
            auto& app = Application::GetInstance();
            if (app.GetDeviceState() == kDeviceStateStarting && !WifiStation::GetInstance().IsConnected()) {
                ResetWifiConfiguration();
            }
            app.ToggleChatState();
        });
        touch_button_.OnPressDown([this]() {
            Application::GetInstance().StartListening();
        });
        touch_button_.OnPressUp([this]() {
            Application::GetInstance().StopListening();
        });

        volume_up_button_.OnClick([this]() {
            auto codec = GetAudioCodec();
            auto volume = codec->output_volume() + 10;
            if (volume > 100) {
                volume = 100;
            }
            codec->SetOutputVolume(volume);
            GetDisplay()->ShowNotification(Lang::Strings::VOLUME + std::to_string(volume));
        });

        volume_up_button_.OnLongPress([this]() {
            GetAudioCodec()->SetOutputVolume(100);
            GetDisplay()->ShowNotification(Lang::Strings::MAX_VOLUME);
        });

        volume_down_button_.OnClick([this]() {
            auto codec = GetAudioCodec();
            auto volume = codec->output_volume() - 10;
            if (volume < 0) {
                volume = 0;
            }
            codec->SetOutputVolume(volume);
            GetDisplay()->ShowNotification(Lang::Strings::VOLUME + std::to_string(volume));
        });

        volume_down_button_.OnLongPress([this]() {
            GetAudioCodec()->SetOutputVolume(0);
            GetDisplay()->ShowNotification(Lang::Strings::MUTED);
        });
    }

    // 物联网初始化,逐步迁移到 MCP 协议
    void InitializeTools() {
        static LampController lamp(LAMP_GPIO);
    }

public:
    A_stepper_motor() :
        boot_button_(BOOT_BUTTON_GPIO),
        touch_button_(TOUCH_BUTTON_GPIO),
        volume_up_button_(VOLUME_UP_BUTTON_GPIO),
        volume_down_button_(VOLUME_DOWN_BUTTON_GPIO) {
        InitializeDisplayI2c();
        InitializeSsd1306Display();
        InitializeButtons();
        InitializeTools();
    }

    virtual Led* GetLed() override {
        static SingleLed led(BUILTIN_LED_GPIO);
        return &led;
    }

    virtual AudioCodec* GetAudioCodec() override {
#ifdef AUDIO_I2S_METHOD_SIMPLEX
        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, I2S_STD_SLOT_RIGHT,  // 扬声器右声道
            AUDIO_I2S_MIC_GPIO_SCK, AUDIO_I2S_MIC_GPIO_WS, AUDIO_I2S_MIC_GPIO_DIN, I2S_STD_SLOT_LEFT); // 左声道 麦克风
#else
        static NoAudioCodecDuplex audio_codec(AUDIO_INPUT_SAMPLE_RATE, AUDIO_OUTPUT_SAMPLE_RATE,
            AUDIO_I2S_GPIO_BCLK, AUDIO_I2S_GPIO_WS, AUDIO_I2S_GPIO_DOUT, AUDIO_I2S_GPIO_DIN);
#endif
        return &audio_codec;
    }

    virtual Display* GetDisplay() override {
        return display_;
    }
};

DECLARE_BOARD(A_stepper_motor);

config.h

#ifndef _BOARD_CONFIG_H_
#define _BOARD_CONFIG_H_

#include <driver/gpio.h>

#define AUDIO_INPUT_SAMPLE_RATE  16000
#define AUDIO_OUTPUT_SAMPLE_RATE 24000

// 如果使用 Duplex I2S 模式,请注释下面一行
#define AUDIO_I2S_METHOD_SIMPLEX

#ifdef AUDIO_I2S_METHOD_SIMPLEX

#define AUDIO_I2S_MIC_GPIO_WS   GPIO_NUM_40     //必要,修改为自己的
#define AUDIO_I2S_MIC_GPIO_SCK  GPIO_NUM_42     //必要,修改为自己的
#define AUDIO_I2S_MIC_GPIO_DIN  GPIO_NUM_41     //必要,修改为自己的
#define AUDIO_I2S_SPK_GPIO_DOUT GPIO_NUM_21     //必要,修改为自己的
#define AUDIO_I2S_SPK_GPIO_BCLK GPIO_NUM_47     //必要,修改为自己的
#define AUDIO_I2S_SPK_GPIO_LRCK GPIO_NUM_48     //必要,修改为自己的

#else

#define AUDIO_I2S_GPIO_WS GPIO_NUM_4            //必要,修改为自己的
#define AUDIO_I2S_GPIO_BCLK GPIO_NUM_5          //必要,修改为自己的
#define AUDIO_I2S_GPIO_DIN  GPIO_NUM_6          //必要,修改为自己的
#define AUDIO_I2S_GPIO_DOUT GPIO_NUM_7          //必要,修改为自己的

#endif

#define BUILTIN_LED_GPIO        GPIO_NUM_NC     //非必要,没有则使用NC
#define BOOT_BUTTON_GPIO        GPIO_NUM_NC
#define TOUCH_BUTTON_GPIO       GPIO_NUM_NC
#define VOLUME_UP_BUTTON_GPIO   GPIO_NUM_NC
#define VOLUME_DOWN_BUTTON_GPIO GPIO_NUM_NC

#define DISPLAY_SDA_PIN GPIO_NUM_8              //必要,修改为自己的
#define DISPLAY_SCL_PIN GPIO_NUM_9              //必要,修改为自己的
#define DISPLAY_WIDTH   128

#define DISPLAY_HEIGHT  32                      //这里直接写死

// #if CONFIG_OLED_SSD1306_128X32
// #define DISPLAY_HEIGHT  32
// #elif CONFIG_OLED_SSD1306_128X64
// #define DISPLAY_HEIGHT  64
// #elif CONFIG_OLED_SH1106_128X64
// #define DISPLAY_HEIGHT  64
// #define SH1106
// #else
// #error "未选择 OLED 屏幕类型"
// #endif

#define DISPLAY_MIRROR_X true
#define DISPLAY_MIRROR_Y true

// A MCP Test: Control a lamp
#define LAMP_GPIO GPIO_NUM_18

#endif // _BOARD_CONFIG_H_

config.json

{
    "target": "esp32s3",
    "builds": [
        {
            "name": "bread-compact-wifi",
            "sdkconfig_append": [
                "CONFIG_OLED_SSD1306_128X32=y"
            ]
        },
        {
            "name": "bread-compact-wifi-128x64",
            "sdkconfig_append": [
                "CONFIG_OLED_SSD1306_128X64=y"
            ]
        }
    ]
}

4.修改main文件夹下的CMakeLists.txt,在133行添加板子的信息,使VsCode可以通过cmake连接到

elseif(CONFIG_BOARD_TYPE_A_STEPPER_MOTOR)
    set(BOARD_TYPE "A-stepper-motor")
    set(BUILTIN_TEXT_FONT font_puhui_basic_20_4)
    set(BUILTIN_ICON_FONT font_awesome_20_4)
    set(DEFAULT_EMOJI_COLLECTION twemoji_64)
4

5.修改main文件夹下的Kconfig.projbuild,在198行添加板子的信息,使VsCode可以选定开发板型号

5

6.选择型号

6

7.打开配置文件进行配置

7_1
7_2
7_3

按下右方向键(->)进入二级菜单

7_4

选中刚刚创建的板子

7_5

按下回车选中,随后切换到英文输入法后按下shift + s 保存

7_6

关闭终端

7_7

8.添加自己写的步进电机控制代码和IO定义

8_1

让cmake可以找到

8_2

进入mcp_server.cc,添加代码

顶端添加路径

#include "Stepper_motor/Little_Rotate.h"

加入代码

    /**
     * @brief 步进电机MCP接入代码
     * 
     */
    AddTool("设置步进电机角度",
        "Rotate the stepper motor to a specific angle.",
        PropertyList({
            Property("angle", kPropertyTypeInteger, 90, 270),    // 角度参数范围
            Property("speed", kPropertyTypeInteger, 1, 500),    // 转速,你可根据自己的需求调整
            Property("direction", kPropertyTypeInteger, 0, 1)    // 方向:0 或 1
        }),
        [this](const PropertyList& properties) -> ReturnValue {

            int angle = properties["angle"].value
<int>();
            int speed = properties["speed"].value
<int>();
            int direction = properties["direction"].value
<int>();

            ESP_LOGI(TAG, "步进电机旋转:角度=%d° 速度=%d 方向=%d",
                     angle, speed, direction);

            // 调用你的步进电机函数
            Little_stepper_rotate_US(angle, speed, direction);

            return true;
        });
8_3

3.准备成功撒花

连接开发板后选择正确的端口,按下小火苗进行构建,烧录,监视

7_1

编译成功

9_2

等待进行烧录后设备自动重启,随后可以对话进行步进电机语音控制了

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇