ESP32-S3-CAM:豆包语音识别文字后控制小车(四)——增加mic拾音后通过豆包语音识别后转文字输出

ESP32-S3-CAM:豆包语音识别文字后控制小车(三)------SD卡本地音频识别转文字

本地音频文件已经识别成功了,接下来就是增加mic拾音转文字功能。

1、上硬件,GPIO口都和之前帖子保持一致

ESP32-S3-CAM:连接 INMP441 麦克风实现音频回环

给kimi说要改一下逻辑了,提示词如下:

现在修改一下代码逻辑,当终端输入 r 文件名 命令 的时候,就从SD卡读对应文件去识别,当终端输入audio的时候,就增加从mic读取 音频到豆包后台识别,分片大小也按照之前代码设置,mic的gpio口设置如下

WS : GPIO 1

SCK : GPIO 2

SD: GPIO 42

后来又给它说:

输入audio命令后只从mic采集3秒音频就结束了,不要一直采集,然后继续等终端输入新的命令

最终代码如下:

cpp 复制代码
/*
 * ESP32-S3 豆包ASR语音识别 - 交互版
 * 支持: 1) SD卡文件识别  2) 麦克风实时识别
 * 
 * 硬件: GOOUUU ESP32-S3-CAM v1.3
 * SD卡: CLK=39, CMD=38, D0=40
 * 麦克风(I2S): WS=GPIO1, SCK=GPIO2, SD=GPIO42
 */

#include <WiFi.h>
#include <WebSocketsClient.h>
#include <SD_MMC.h>
#include <ArduinoJson.h>
#include <driver/i2s.h>

// ============== 配置区域 ==============
const char* ssid = "你的WiFi名称";
const char* password = "你的WiFi密码";

// 豆包ASR配置
const char* appid = "你的 APP ID";
const char* token = "你的 Access Token";
const char* cluster = "volcengine_input_common";
const char* ws_host = "openspeech.bytedance.com";
const int ws_port = 443;
const char* ws_path = "/api/v2/asr";

// SD卡引脚
#define SD_CLK  39
#define SD_CMD  38
#define SD_D0   40

// 麦克风I2S引脚
#define I2S_WS      1
#define I2S_SCK     2
#define I2S_SD      42
#define I2S_PORT    I2S_NUM_0

// 音频配置
const int audio_rate = 16000;
const int audio_bits = 16;
const int audio_channel = 2;

// 分片大小
const size_t CHUNK_SIZE = 64000;  // 64KB大分片

// 协议常量
#define PROTOCOL_VERSION 0x01
#define DEFAULT_HEADER_SIZE 0x01
#define CLIENT_FULL_REQUEST 0x01
#define CLIENT_AUDIO_ONLY_REQUEST 0x02
#define SERVER_FULL_RESPONSE 0x09
#define SERVER_ACK 0x0B
#define SERVER_ERROR_RESPONSE 0x0F
#define NO_SEQUENCE 0x00
#define NEG_SEQUENCE 0x02
#define JSON_SERIALIZATION 0x01
#define NO_COMPRESSION 0x00

// ============== 全局变量 ==============
WebSocketsClient webSocket;
bool ws_connected = false;
bool asr_completed = false;
bool asr_running = false;
bool result_displayed = false;  // 防止重复打印结果
String recognition_result = "";

// SD卡文件模式
File audio_file;
size_t audio_total_size = 0;
size_t audio_sent_size = 0;
String target_filename = "";

// 麦克风模式
bool mic_mode = false;
int16_t* mic_buffer = nullptr;
const int MIC_BUFFER_SAMPLES = 1024;  // 每次采集1024样本
unsigned long mic_start_time = 0;     // 录音开始时间
const unsigned long MIC_RECORD_DURATION = 5000;  // 录音时长3秒

// ============== 函数声明 ==============
bool initSD();
void listSDFiles();
void showPrompt();
void processCommand(String cmd);
bool loadAndRecognizeFile(String filename);
bool startMicRecognition();
void initWebSocket();
void webSocketEvent(WStype_t type, uint8_t * payload, size_t length);
void sendFullClientRequest(bool from_mic);
void sendNextChunk();
void sendMicAudio();
void sendLastMicChunk();  // 发送麦克风结束标记
void parseResponse(uint8_t* data, size_t len);
void generateHeader(uint8_t* header, uint8_t msg_type, uint8_t flags);
bool initI2SMic();
void stopI2SMic();

// ============== 协议头生成 ==============
void generateHeader(uint8_t* header, uint8_t msg_type, uint8_t flags) {
    header[0] = (PROTOCOL_VERSION << 4) | DEFAULT_HEADER_SIZE;
    header[1] = (msg_type << 4) | flags;
    header[2] = (JSON_SERIALIZATION << 4) | NO_COMPRESSION;
    header[3] = 0x00;
}

// ============== 设置 ==============
void setup() {
    Serial.begin(115200);
    delay(1000);

    Serial.println("\n========================================");
    Serial.println("ESP32-S3 豆包ASR语音识别(交互版)");
    Serial.println("========================================");
    Serial.println("命令:");
    Serial.println("  r <文件名>  - 识别SD卡中的音频文件");
    Serial.println("  audio       - 从麦克风实时识别");
    Serial.println("  list        - 列出SD卡文件");
    Serial.println("  help        - 显示帮助");
    Serial.println("========================================\n");

    // 初始化SD卡
    if (!initSD()) {
        Serial.println("⚠️ SD卡初始化失败,文件模式不可用");
    }

    // 连接WiFi
    Serial.print("[WiFi] 连接 ");
    Serial.print(ssid);
    Serial.print(" ...");
    WiFi.begin(ssid, password);
    int retry = 0;
    while (WiFi.status() != WL_CONNECTED && retry < 30) {
        delay(500);
        Serial.print(".");
        retry++;
    }
    if (WiFi.status() != WL_CONNECTED) {
        Serial.println(" ❌ 失败");
        while (1) delay(1000);
    }
    Serial.println(" ✅ 已连接");
    Serial.print("[WiFi] IP: ");
    Serial.println(WiFi.localIP());

    // 初始化麦克风缓冲区
    mic_buffer = (int16_t*)malloc(MIC_BUFFER_SAMPLES * sizeof(int16_t));
    if (!mic_buffer) {
        Serial.println("⚠️ 麦克风缓冲区分配失败");
    }

    showPrompt();
}

// ============== 主循环 ==============
void loop() {
    webSocket.loop();

    // 处理串口命令
    if (Serial.available()) {
        String cmd = Serial.readStringUntil('\n');
        cmd.trim();
        if (cmd.length() > 0) {
            processCommand(cmd);
        }
    }

    // 麦克风模式:采集5秒后自动结束
    if (mic_mode && ws_connected && !asr_completed) {
        // 检查是否超过5秒
        if (millis() - mic_start_time >= MIC_RECORD_DURATION) {
            Serial.println("\n[MIC] 3秒录音时间到,停止采集");
            // 发送最后一片标记
            sendLastMicChunk();
            mic_mode = false;
        } else {
            sendMicAudio();
        }
    }

    // 识别完成处理(只执行一次)
    if (asr_completed && !result_displayed) {
        result_displayed = true;  // 标记已显示结果

        Serial.println("\n========================================");
        Serial.println("🎉 ASR识别完成!");
        Serial.println("----------------------------------------");
        Serial.print("📢 最终识别结果: ");
        Serial.println(recognition_result);
        Serial.println("========================================");

        // 断开WebSocket并禁用自动重连
        webSocket.setReconnectInterval(0);  // 禁用自动重连
        webSocket.disconnect();
        ws_connected = false;

        // 清理
        if (audio_file) audio_file.close();
        if (mic_buffer) stopI2SMic();  // 麦克风模式清理

        asr_running = false;
        mic_mode = false;

        showPrompt();
    }
}

// ============== 显示提示符 ==============
void showPrompt() {
    Serial.println("\n[等待命令] > ");
}

// ============== 处理命令 ==============
void processCommand(String cmd) {
    cmd.toLowerCase();

    if (cmd.startsWith("r ")) {
        // 识别文件
        String filename = cmd.substring(2);
        filename.trim();
        if (!filename.startsWith("/")) filename = "/" + filename;
        result_displayed = false;  // 重置标志
        loadAndRecognizeFile(filename);
    }
    else if (cmd == "audio") {
        // 麦克风识别
        result_displayed = false;  // 重置标志
        startMicRecognition();
    }
    else if (cmd == "list") {
        // 列出文件
        listSDFiles();
        showPrompt();
    }
    else if (cmd == "help") {
        Serial.println("命令:");
        Serial.println("  r <文件名>  - 识别SD卡音频文件 (如: r audio1.wav)");
        Serial.println("  audio       - 从麦克风实时识别");
        Serial.println("  list        - 列出SD卡文件");
        Serial.println("  help        - 显示帮助");
        showPrompt();
    }
    else {
        Serial.println("❌ 未知命令,输入 help 查看帮助");
        showPrompt();
    }
}

// ============== SD卡初始化 ==============
bool initSD() {
    Serial.println("[SD] 初始化SD卡...");
    SD_MMC.setPins(SD_CLK, SD_CMD, SD_D0);
    if (!SD_MMC.begin("/sdcard", true)) {
        Serial.println("[SD] ❌ 失败");
        return false;
    }
    uint8_t type = SD_MMC.cardType();
    Serial.print("[SD] 类型: ");
    if (type == CARD_SD) Serial.println("SD");
    else if (type == CARD_SDHC) Serial.println("SDHC");
    else if (type == CARD_MMC) Serial.println("MMC");
    else Serial.println("未知");
    Serial.printf("[SD] 容量: %llu MB\n", SD_MMC.cardSize() / 1048576);
    return true;
}

// ============== 列出SD卡文件 ==============
void listSDFiles() {
    File root = SD_MMC.open("/");
    if (!root || !root.isDirectory()) {
        Serial.println("[SD] ❌ 无法打开目录");
        return;
    }
    Serial.println("\n[SD] 文件列表:");
    int count = 0;
    File f = root.openNextFile();
    while (f) {
        if (!f.isDirectory()) {
            Serial.printf("  [FILE] %-20s %6d KB\n", f.name(), f.size() / 1024);
            count++;
        }
        f = root.openNextFile();
    }
    Serial.printf("[SD] 共 %d 个文件\n", count);
}

// ============== 加载并识别文件 ==============
bool loadAndRecognizeFile(String filename) {
    if (asr_running) {
        Serial.println("❌ 当前有识别任务在运行,请等待完成");
        return false;
    }

    Serial.printf("\n[文件] 准备识别: %s\n", filename.c_str());

    if (!SD_MMC.exists(filename)) {
        Serial.println("❌ 文件不存在");
        showPrompt();
        return false;
    }

    audio_file = SD_MMC.open(filename, FILE_READ);
    if (!audio_file) {
        Serial.println("❌ 无法打开文件");
        showPrompt();
        return false;
    }

    audio_total_size = audio_file.size();
    audio_sent_size = 0;
    target_filename = filename;
    mic_mode = false;

    Serial.printf("[文件] 大小: %d bytes (%.1f KB)\n", audio_total_size, audio_total_size / 1024.0);

    // 重置状态
    asr_completed = false;
    asr_running = true;
    recognition_result = "";

    // 连接WebSocket并开始识别
    Serial.println("[ASR] 连接服务器...");
    initWebSocket();

    return true;
}

// ============== 初始化麦克风 ==============
bool initI2SMic() {
    Serial.println("[MIC] 初始化I2S麦克风...");

    i2s_config_t i2s_config = {
        .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX),
        .sample_rate = audio_rate,
        .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
        .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT,
        .communication_format = I2S_COMM_FORMAT_STAND_I2S,
        .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
        .dma_buf_count = 4,
        .dma_buf_len = 1024,
        .use_apll = false,
        .tx_desc_auto_clear = false,
        .fixed_mclk = 0
    };

    i2s_pin_config_t pin_config = {
        .bck_io_num = I2S_SCK,
        .ws_io_num = I2S_WS,
        .data_out_num = I2S_PIN_NO_CHANGE,
        .data_in_num = I2S_SD
    };

    esp_err_t err = i2s_driver_install(I2S_PORT, &i2s_config, 0, NULL);
    if (err != ESP_OK) {
        Serial.printf("[MIC] ❌ I2S驱动安装失败: %d\n", err);
        return false;
    }

    err = i2s_set_pin(I2S_PORT, &pin_config);
    if (err != ESP_OK) {
        Serial.printf("[MIC] ❌ I2S引脚设置失败: %d\n", err);
        i2s_driver_uninstall(I2S_PORT);
        return false;
    }

    Serial.println("[MIC] ✅ I2S麦克风初始化成功");
    return true;
}

// ============== 停止麦克风 ==============
void stopI2SMic() {
    i2s_driver_uninstall(I2S_PORT);
    Serial.println("[MIC] I2S已停止");
}

// ============== 启动麦克风识别 ==============
bool startMicRecognition() {
    if (asr_running) {
        Serial.println("❌ 当前有识别任务在运行,请等待完成");
        return false;
    }

    Serial.println("\n[MIC] 启动麦克风识别...");

    if (!initI2SMic()) {
        showPrompt();
        return false;
    }

    mic_mode = true;
    asr_completed = false;
    asr_running = true;
    recognition_result = "";
    mic_start_time = millis();  // 记录开始时间

    Serial.println("[MIC] 请开始说话(3秒自动停止)...");

    // 连接WebSocket
    Serial.println("[ASR] 连接服务器...");
    initWebSocket();

    return true;
}

// ============== WebSocket初始化 ==============
void initWebSocket() {
    webSocket.beginSSL(ws_host, ws_port, ws_path);
    String auth = "Authorization: Bearer; ";
    auth += token;
    webSocket.setExtraHeaders(auth.c_str());
    webSocket.onEvent(webSocketEvent);
    webSocket.setReconnectInterval(5000);  // 启用自动重连(5秒)
}

// ============== WebSocket事件处理 ==============
void webSocketEvent(WStype_t type, uint8_t * payload, size_t length) {
    switch(type) {
        case WStype_DISCONNECTED:
            Serial.println("[WS] ❌ 断开");
            ws_connected = false;
            break;
        case WStype_CONNECTED:
            Serial.println("[WS] ✅ 已连接");
            ws_connected = true;
            sendFullClientRequest(mic_mode);
            break;
        case WStype_BIN:
            parseResponse(payload, length);
            break;
        case WStype_ERROR:
            Serial.println("[WS] ❌ 错误");
            break;
        default:
            break;
    }
}

// ============== 发送配置 ==============
void sendFullClientRequest(bool from_mic) {
    Serial.println("[ASR] 📤 发送配置...");

    JsonDocument doc;
    doc["app"]["appid"] = appid;
    doc["app"]["token"] = token;
    doc["app"]["cluster"] = cluster;
    doc["user"]["uid"] = "esp32_asr";
    doc["request"]["reqid"] = "esp32-" + String(millis());
    doc["request"]["nbest"] = 1;
    doc["request"]["workflow"] = "audio_in,resample,partition,vad,fe,decode,itn,nlu_punctuate";
    doc["request"]["show_utterances"] = false;
    doc["request"]["result_type"] = "full";
    doc["request"]["sequence"] = 1;
    doc["audio"]["format"] = from_mic ? "raw" : "wav";
    doc["audio"]["rate"] = audio_rate;
    doc["audio"]["language"] = "zh-CN";
    doc["audio"]["bits"] = audio_bits;
    doc["audio"]["channel"] = from_mic ? 1 : audio_channel;  // 麦克风通常是单声道
    doc["audio"]["codec"] = "raw";

    String json;
    serializeJson(doc, json);

    size_t msg_len = 4 + 4 + json.length();
    uint8_t* msg = (uint8_t*)malloc(msg_len);
    generateHeader(msg, CLIENT_FULL_REQUEST, NO_SEQUENCE);
    msg[4] = (json.length() >> 24) & 0xFF;
    msg[5] = (json.length() >> 16) & 0xFF;
    msg[6] = (json.length() >> 8) & 0xFF;
    msg[7] = json.length() & 0xFF;
    memcpy(msg + 8, json.c_str(), json.length());

    webSocket.sendBIN(msg, msg_len);
    free(msg);

    Serial.println("[ASR] ✅ 配置已发送");

    // 如果是文件模式,立即开始发送第一片音频
    if (!from_mic && audio_file) {
        delay(100);  // 稍等服务器响应
        sendNextChunk();
    }
}

// ============== 发送文件下一片 ==============
void sendNextChunk() {
    if (!audio_file || !asr_running) return;

    size_t remaining = audio_total_size - audio_sent_size;
    if (remaining == 0) {
        // 文件发送完成,发送结束标记
        Serial.println("[ASR] 文件读取完成,等待最终结果...");
        return;
    }

    size_t chunk = (remaining > CHUNK_SIZE) ? CHUNK_SIZE : remaining;
    bool is_last = (remaining <= CHUNK_SIZE);

    // 从文件读取
    uint8_t* buffer = (uint8_t*)malloc(chunk);
    if (!buffer) {
        Serial.println("[ERR] ❌ 内存不足");
        return;
    }

    size_t read = audio_file.read(buffer, chunk);
    if (read != chunk) {
        Serial.println("[ERR] ❌ 读取失败");
        free(buffer);
        return;
    }

    // 构建消息
    size_t msg_len = 4 + 4 + chunk;
    uint8_t* msg = (uint8_t*)malloc(msg_len);
    uint8_t flags = is_last ? NEG_SEQUENCE : NO_SEQUENCE;
    generateHeader(msg, CLIENT_AUDIO_ONLY_REQUEST, flags);
    msg[4] = (chunk >> 24) & 0xFF;
    msg[5] = (chunk >> 16) & 0xFF;
    msg[6] = (chunk >> 8) & 0xFF;
    msg[7] = chunk & 0xFF;
    memcpy(msg + 8, buffer, chunk);

    webSocket.sendBIN(msg, msg_len);

    free(buffer);
    free(msg);

    audio_sent_size += chunk;

    Serial.printf("[ASR] 📤 已发送 %d/%d KB (%d%%)%s\n", 
        audio_sent_size / 1024, audio_total_size / 1024,
        audio_sent_size * 100 / audio_total_size,
        is_last ? " [最后一片]" : "");
}

// ============== 发送最后一片麦克风音频(带结束标记)==============
void sendLastMicChunk() {
    if (!mic_buffer) return;

    Serial.println("[MIC] 发送结束标记...");

    // 发送一个空包或静音包作为结束标记
    size_t msg_len = 4 + 4;  // header + size = 8 bytes (空payload)
    uint8_t* msg = (uint8_t*)malloc(msg_len);
    if (!msg) return;

    generateHeader(msg, CLIENT_AUDIO_ONLY_REQUEST, NEG_SEQUENCE);  // NEG_SEQUENCE表示最后一片
    msg[4] = 0;
    msg[5] = 0;
    msg[6] = 0;
    msg[7] = 0;  // payload size = 0

    webSocket.sendBIN(msg, msg_len);
    free(msg);

    Serial.println("[MIC] 结束标记已发送,等待识别结果...");
}

// ============== 发送麦克风音频 ==============
void sendMicAudio() {
    if (!mic_buffer || !asr_running) return;

    // 从I2S读取数据
    size_t bytes_read = 0;
    esp_err_t err = i2s_read(I2S_PORT, mic_buffer, MIC_BUFFER_SAMPLES * sizeof(int16_t), &bytes_read, portMAX_DELAY);

    if (err != ESP_OK || bytes_read == 0) return;

    int samples = bytes_read / sizeof(int16_t);

    // 构建消息(实时发送,不分片累积)
    size_t msg_len = 4 + 4 + bytes_read;
    uint8_t* msg = (uint8_t*)malloc(msg_len);
    if (!msg) return;

    generateHeader(msg, CLIENT_AUDIO_ONLY_REQUEST, NO_SEQUENCE);
    msg[4] = (bytes_read >> 24) & 0xFF;
    msg[5] = (bytes_read >> 16) & 0xFF;
    msg[6] = (bytes_read >> 8) & 0xFF;
    msg[7] = bytes_read & 0xFF;
    memcpy(msg + 8, mic_buffer, bytes_read);

    webSocket.sendBIN(msg, msg_len);
    free(msg);

    static int mic_packets = 0;
    mic_packets++;
    if (mic_packets % 50 == 0) {
        Serial.print(".");  // 每50包打印一个点表示正在采集
    }
}

// ============== 解析响应 ==============
void parseResponse(uint8_t* data, size_t len) {
    if (len < 8) return;

    uint8_t msg_type = data[1] >> 4;
    uint8_t serialization = data[2] >> 4;
    uint8_t header_size = data[0] & 0x0F;

    size_t payload_offset = header_size * 4;
    if (len < payload_offset + 4) return;

    int32_t payload_size = ((int32_t)data[payload_offset] << 24) |
                           ((int32_t)data[payload_offset + 1] << 16) |
                           ((int32_t)data[payload_offset + 2] << 8) |
                           ((int32_t)data[payload_offset + 3]);

    if (payload_size <= 0 || len < payload_offset + 4 + payload_size) return;

    uint8_t* payload = data + payload_offset + 4;

    if (serialization == JSON_SERIALIZATION) {
        JsonDocument doc;
        DeserializationError err = deserializeJson(doc, payload, payload_size);

        if (err) return;

        int code = doc["code"] | -1;
        int sequence = doc["sequence"] | 0;

        if (code == 1000) {
            // 提取文本
            JsonArray arr = doc["result"].as<JsonArray>();
            if (arr.size() > 0) {
                const char* txt = arr[0]["text"];
                if (txt && strlen(txt) > 0) {
                    recognition_result = String(txt);
                    Serial.printf("\n[识别] %s\n", txt);
                }
            }

            // 检查是否完成
            if (sequence < 0) {
                asr_completed = true;
                Serial.println("[ASR] 收到最终响应标记(sequence<0)");
                return;  // 立即返回,不再处理后续逻辑
            }

            // 文件模式:继续发送下一片
            if (!mic_mode && audio_file) {
                sendNextChunk();
            }
            // 麦克风模式:继续采集(自动在loop中处理)

        } else {
            const char* msg = doc["message"] | "Unknown";
            Serial.printf("[ERR] %d: %s\n", code, msg);
        }
    }
}

测试结果如下:

bash 复制代码
ESP-ROM:esp32s3-20210327
Build:Mar 27 2021
rst:0x1 (POWERON),boot:0x8 (SPI_FAST_FLASH_BOOT)
SPIWP:0xee
mode:DIO, clock div:1
load:0x3fce2820,len:0x10cc
load:0x403c8700,len:0xc2c
load:0x403cb700,len:0x30c0
entry 0x403c88b8

========================================
ESP32-S3 豆包ASR语音识别(交互版)
========================================
命令:
  r <文件名>  - 识别SD卡中的音频文件
  audio       - 从麦克风实时识别
  list        - 列出SD卡文件
  help        - 显示帮助
========================================

[SD] 初始化SD卡...
[SD] 类型: SDHC
[SD] 容量: 15200 MB
[WiFi] 连接 rm1234 ....... ✅ 已连接
[WiFi] IP: 192.168.137.241

[等待命令] > 

[文件] 准备识别: /hello.wav
[文件] 大小: 288044 bytes (281.3 KB)
[ASR] 连接服务器...
[WS] ✅ 已连接
[ASR] 📤 发送配置...
[ASR] ✅ 配置已发送
[ASR] 📤 已发送 62/281 KB (22%)
[ASR] 📤 已发送 125/281 KB (44%)
[ASR] 📤 已发送 187/281 KB (66%)
[ASR] 📤 已发送 250/281 KB (88%)
[ASR] 📤 已发送 281/281 KB (100%) [最后一片]
[ASR] 文件读取完成,等待最终结果...

[识别] 你好!
[ASR] 收到最终响应标记(sequence<0)

========================================
🎉 ASR识别完成!
----------------------------------------
📢 最终识别结果: 你好!
========================================
[WS] ❌ 断开
E (16913) i2s(legacy): i2s_driver_uninstall(1586): I2S port 0 has not installed
[MIC] I2S已停止

[等待命令] > 
[WS] ✅ 已连接
[ASR] 📤 发送配置...
[ASR] ✅ 配置已发送

[MIC] 启动麦克风识别...
[MIC] 初始化I2S麦克风...
[MIC] ✅ I2S麦克风初始化成功
[MIC] 请开始说话(3秒自动停止)...
[ASR] 连接服务器...
[WS] ✅ 已连接
[ASR] 📤 发送配置...
[ASR] ✅ 配置已发送

[识别] 小

[识别] 小

[识别] 小
.
[识别] 小

[识别] 小车

[识别] 小车

[识别] 小车

[识别] 小车

[识别] 小车

[识别] 小车

[识别] 小车

[识别] 小车

[识别] 小车

[识别] 小车前进

[识别] 小车前进

[识别] 小车前进

[识别] 小车前进

[识别] 小车前进!

[识别] 小车前进!

[识别] 小车前进!

[识别] 小车前进!

[识别] 小车前进!

[识别] 小车前进!

[识别] 小车前进!

[识别] 小车前进!

[识别] 小车前进!

[识别] 小车前进!

[识别] 小车前进!

[识别] 小车前进!

[识别] 小车前进!

[MIC] 3秒录音时间到,停止采集
[MIC] 发送结束标记...
[MIC] 结束标记已发送,等待识别结果...

[识别] 小车前进!

[识别] 小车前进!

[识别] 小车前进!

[识别] 小车前进!

[识别] 小车前进!
[ASR] 收到最终响应标记(sequence<0)

========================================
🎉 ASR识别完成!
----------------------------------------
📢 最终识别结果: 小车前进!
========================================
[WS] ❌ 断开
[MIC] I2S已停止

[等待命令] > 
[WS] ✅ 已连接
[ASR] 📤 发送配置...
[ASR] ✅ 配置已发送

[MIC] 启动麦克风识别...
[MIC] 初始化I2S麦克风...
[MIC] ✅ I2S麦克风初始化成功
[MIC] 请开始说话(3秒自动停止)...
[ASR] 连接服务器...
.[WS] ✅ 已连接
[ASR] 📤 发送配置...
[ASR] ✅ 配置已发送

[识别] 小

[识别] 小

[识别] 小

[识别] 小车

[识别] 小车

[识别] 小车

[识别] 小车

[识别] 小车

[识别] 小车

[识别] 小车后

[识别] 小车后

[识别] 小车后

[识别] 小车后腿

[识别] 小车后腿

[识别] 小车后腿

[识别] 小车后腿

[识别] 小车后腿

[识别] 小车后退!

[识别] 小车后退!

[识别] 小车后退!

[识别] 小车后退!

[识别] 小车后退!

[识别] 小车后退!

[识别] 小车后退!

[识别] 小车后退!

[识别] 小车后退!

[识别] 小车后退!

[MIC] 3秒录音时间到,停止采集
[MIC] 发送结束标记...
[MIC] 结束标记已发送,等待识别结果...

[识别] 小车后退!

[识别] 小车后退!

[识别] 小车后退!

[识别] 小车后退!

[识别] 小车后退!

[识别] 小车后退!
[ASR] 收到最终响应标记(sequence<0)

========================================
🎉 ASR识别完成!
----------------------------------------
📢 最终识别结果: 小车后退!
========================================
[WS] ❌ 断开
[MIC] I2S已停止

[等待命令] > 
[WS] ✅ 已连接
[ASR] 📤 发送配置...
[ASR] ✅ 配置已发送

下一步,连接L298N电机,控制小车前进和后退。

相关推荐
爱上珍珠的贝壳2 小时前
ESP32-S3-CAM:豆包语音识别文字后控制小车(一)——注册豆包火山引擎开发者接口
人工智能·语音识别·智能硬件·火山引擎·esp32-s3·豆包语音
Lucas_coding3 小时前
【语音相关ASR】FunASR 离线语音识别与FunASR热词优化
人工智能·语音识别·xcode
AI英德西牛仔3 小时前
手机怎么把AI对话导出
人工智能·ai·智能手机·豆包·deepseek·ds随心转
爱上珍珠的贝壳3 小时前
ESP32-S3-CAM:豆包语音识别文字后控制小车(三)——SD卡本地音频识别转文字
人工智能·音频·语音识别·智能硬件·esp32-s3
reasonsummer4 小时前
【教学类-160-05】20260412 AI视频培训-练习5“豆包AI视频《幼儿园之父:福禄贝尔(英声中字)》+豆包图片风格:伦勃朗(古典油画)竖版”
音视频·豆包·通义万相
宝贝儿好15 小时前
【LLM】第二章:文本表示:词袋模型、小案例:基于文本的推荐系统(酒店推荐)
人工智能·python·深度学习·神经网络·自然语言处理·机器人·语音识别
EMQX21 小时前
Everything Will Flow:面向 AI 的新一代融合消息流平台 FlowMQ 正式发布
物联网·mqtt·智能硬件·flowmq
憨波个1 天前
【说话人日志】从 LSTM attractor 到 Transformer attractor:EEND-TA
人工智能·深度学习·lstm·transformer·音频·语音识别
antzou1 天前
语音识别 (ASR)
人工智能·语音识别·onnx·asr·paraformer