作為一名電子愛好者和創(chuàng)客,我一直對智能語音交互技術(shù)充滿興趣。最近,我決定基于ESP32開發(fā)板,DIY一個語音智能交互機器人。這次項目不僅讓我深入了解了語音識別和交互技術(shù)下面,我將詳細分享我的開發(fā)過程以及最終成果。
其中 感謝 瑾sing 大佬的指點與幫助
一、項目規(guī)劃
1. 項目目標
我的目標是制作一個能夠通過語音指令交互的智能機器人,具備以下功能:
語音識別:通過麥克風(fēng)采集語音并轉(zhuǎn)換為文本。
語音反饋:通過喇叭播放語音回復(fù)。
顯示交互信息:通過TFT屏幕顯示當前狀態(tài)和交互內(nèi)容。
2. 所需元件
為了實現(xiàn)上述功能,我選擇了以下核心元件:
2.1 ESP32開發(fā)板:作為主控芯片,負責(zé)處理語音識別、交互邏輯和驅(qū)動外設(shè)。
2.2 1.8寸TFT彩屏(ST7735驅(qū)動):用于顯示交互信息和狀態(tài)。
2.3 MAX98357音頻放大器:驅(qū)動喇叭播放語音反饋。
2.4 INMP441全向麥克風(fēng)模塊:用于高精度語音采集。
2.5 3W喇叭:播放語音回復(fù)。
二、元件展示
1. ESP32開發(fā)板ESP32是一款功能強大的Wi-Fi和藍牙雙模芯片,非常適合物聯(lián)網(wǎng)和智能交互項目。它的引腳豐富,支持多種外設(shè)接口。
2. 1.8寸TFT彩屏(ST7735驅(qū)動)這款屏幕分辨率高,色彩鮮艷,適合顯示交互信息。它的SPI接口與ESP32兼容,接線簡單。
3. MAX98357音頻放大器MAX98357是一款高效的I2S數(shù)字音頻放大器,可以直接驅(qū)動3W喇叭,音質(zhì)清晰。
4. INMP441全向麥克風(fēng)模塊INMP441是一款高性能的數(shù)字麥克風(fēng),支持I2S接口,能夠高精度采集語音信號。
5. 3W喇叭這款喇叭體積小巧,但音量大,適合嵌入式項目。
三、API選擇與注冊
1. KIMI AI模型API
KIMI是一款強大的AI模型,支持自然語言處理和對話生成。通過其API,我可以實現(xiàn)智能對話功能。
官網(wǎng):KIMI API官網(wǎng)
請求方式:POST
功能:發(fā)送用戶輸入的文本,獲取AI生成的回復(fù)。
2. 百度智能云語音服務(wù)
百度智能云提供了語音識別和語音合成服務(wù),非常適合用于語音交互項目。
官網(wǎng):百度智能云平臺
語音識別:POST請求,將語音文件轉(zhuǎn)換為文本。
語音合成:GET請求,將文本轉(zhuǎn)換為語音文件。
四、API調(diào)試工具推薦:Postman
Postman是一款非常流行的API調(diào)試工具,支持多種請求方式(GET、POST等),并且可以方便地查看請求和響應(yīng)數(shù)據(jù)。以下是使用Postman調(diào)試API的基本步驟:
下載并安裝Postman:Postman官網(wǎng)。
創(chuàng)建一個新的請求,選擇請求方式(GET或POST)。
填寫API的URL、請求頭和請求體。
發(fā)送請求并查看響應(yīng)結(jié)果。
五、、在ESP32中集成API調(diào)用
String get_kimi(String question)
{
HTTPClient http1 ;
http1.setTimeout(20000);
http1.begin(Kimi_url);
http1.addHeader("Content-Type", "application/json");
http1.addHeader("Authorization", "sk-4cyiL5............................................................."); //注意得填寫你的碼
String body="{\"model\":\"moonshot-v1-8k\",\"messages\":[{\"role\":\"system\",\"content\":\"你是我的AI助手小愛,你必須用中文回答且字數(shù)不超過85個\"},{\"role\":\"user\",\"content\":\"" + question + "\"},{\"role\": \"assistant\",\"name\":\" 小南\", \"content\":\"\", \"partial\": true}],\"temperature\":0.3}";
int httpResponseCode = http1.POST(body);
if(httpResponseCode == 200)
{
String response = http1.getString();
http1.end();
//Serial.println(response);
StaticJsonDocument<1024> json1;
deserializeJson(json1,response);
String json_get1 = json1["choices"];
deserializeJson(json1,json_get1);
String message = json1[0]["message"].as<String>();
deserializeJson(json1,message);
String respone = json1["content"];
//Serial.println(respone);
return respone ;
}
else
{
http1.end();
//Serial.println("error");
return "你問的太快了詢問不能頻繁當前為一分鐘三到四次詢問)";//(kimi的api比較菜一分鐘只能問他3個問題)
}
}
void callBaiduTextToSpeech(String text) {
HTTPClient http;
String url = "https://tsn.baidu.com/text2audio?tex=" + text + "&tok=YOUR_ACCESS_TOKEN&cuid=YOUR_DEVICE_ID&ctp=1&lan=zh";
http.begin(url);
int httpResponseCode = http.GET();
if (httpResponseCode == 200) {
// 保存語音文件并播放
File file = SPIFFS.open("/output.mp3", FILE_WRITE);
http.writeToStream(&file);
file.close();
playAudio("/output.mp3");
} else {
Serial.println("Error calling Baidu Text-to-Speech API");
}
http.end();
}
六、語音數(shù)據(jù)采集
1. 使用driver/i2s.h
庫與INMP441麥克風(fēng)
INMP441是一款高性能的數(shù)字麥克風(fēng),支持I2S接口。為了采集語音數(shù)據(jù),我使用了ESP32的driver/i2s.h
庫。以下是具體實現(xiàn)步驟:
1.1 初始化I2S
#include <driver/i2s.h>
void setupI2S() {
i2s_config_t i2s_config = {
.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX),
.sample_rate = 8000,
.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 = 0,
.dma_buf_count = 8,
.dma_buf_len = 64,
.use_apll = false
};
i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL);
i2s_set_pin(I2S_NUM_0, NULL);
}
1.2 采集語音數(shù)據(jù)
由于driver/i2s.h
庫是雙聲道設(shè)計,而INMP441是單聲道麥克風(fēng),因此采集到的數(shù)據(jù)只有左聲道有效,右聲道數(shù)據(jù)為0。為了解決這個問題,我采用了以下兩種方法:
方法1:增加數(shù)據(jù)量
將采樣數(shù)據(jù)量增加到兩倍(例如3200個數(shù)據(jù)),這樣可以確保采集到足夠的有效數(shù)據(jù),但會浪費資源。
方法2:設(shè)置兩倍長度的數(shù)組
在接口函數(shù)中填入兩倍長度的數(shù)組,確保采集到足夠的有效數(shù)據(jù)。
void captureAudio(int16_t* buffer, size_t bufferSize) {
size_t bytesRead;
i2s_read(I2S_NUM_0, buffer, bufferSize * 2, &bytesRead, portMAX_DELAY);
}
2、數(shù)據(jù)上傳
2.1. 編碼為Base64
百度智能云的語音識別API要求上傳的音頻數(shù)據(jù)必須為Base64編碼。以下是編碼實現(xiàn)的代碼:
#include <base64.h>
String encodeAudioToBase64(int16_t* audioData, size_t dataSize) {
size_t encodedSize = Base64.encodedLength(dataSize * 2);
char encodedData[encodedSize];
Base64.encode((uint8_t*)audioData, dataSize * 2, encodedData);
return String(encodedData);
}
2. 上傳音頻數(shù)據(jù)
以下是上傳音頻數(shù)據(jù)到百度智能云的代碼:
#include <WiFi.h>
#include <HTTPClient.h>
void uploadAudioToBaidu(String base64Data) {
HTTPClient http;
http.begin("https://vop.baidu.com/server_api");
http.addHeader("Content-Type", "application/json");
String requestBody = "{\"format\":\"wav\",\"rate\":16000,\"channel\":1,\"token\":\"YOUR_ACCESS_TOKEN\",\"cuid\":\"YOUR_DEVICE_ID\",\"speech\":\"" + base64Data + "\"}";
int httpResponseCode = http.POST(requestBody);
if (httpResponseCode == 200) {
String response = http.getString();
Serial.println("Baidu Speech Recognition: " + response);
} else {
Serial.println("Error calling Baidu Speech Recognition API");
}
http.end();
}
七、文字轉(zhuǎn)語音
1. 使用audio.h
庫播放MP3
百度智能云的語音合成API返回的是MP3格式的音頻文件,我使用了audio.h
庫來播放這些文件。以下是實現(xiàn)代碼:
#include <Audio.h>
Audio audio;
void playTextToSpeech(String text) {
String url = "https://tsn.baidu.com/text2audio?tex=" + text + "&tok=YOUR_ACCESS_TOKEN&cuid=YOUR_DEVICE_ID&ctp=1&lan=zh";
audio.connecttohost(url.c_str());
}
void loop() {
audio.loop();
}
八、硬件連接與引腳配置
1. MAX98357音頻放大器(語音輸出)
MAX98357是一款I(lǐng)2S數(shù)字音頻放大器,用于驅(qū)動喇叭播放語音。以下是其接線方法:
I2S_DOUT:連接到ESP32的GPIO 25(數(shù)據(jù)輸出)。
I2S_BCLK:連接到ESP32的GPIO 27(位時鐘)。
I2S_LRC:連接到ESP32的GPIO 26(左右聲道時鐘)。
喇叭:連接到MAX98357的喇叭輸出端子(正負極不分)。
#define I2S_DOUT 25 #define I2S_BCLK 27 #define I2S_LRC 26
2. INMP441麥克風(fēng)(語音輸入)
INMP441是一款高性能的數(shù)字麥克風(fēng),用于采集語音信號。以下是其接線方法:
I2S_WS:連接到ESP32的GPIO 32(字選擇)。
I2S_SD:連接到ESP32的GPIO 35(數(shù)據(jù)輸入)。
I2S_SCK:連接到ESP32的GPIO 33(串行時鐘)。
L/R:接地(選擇左聲道)。
#define I2S_WS 32 #define I2S_SD 35 #define I2S_SCK 33
3. TFT屏幕(顯示交互信息)
TFT屏幕用于顯示語音交互信息和系統(tǒng)狀態(tài)。以下是其接線方法:
TFT_MOSI:連接到ESP32的GPIO 2(主輸出從輸入)。
TFT_SCLK:連接到ESP32的GPIO 15(串行時鐘)。
TFT_CS:連接到ESP32的GPIO 17(片選)。
TFT_DC:連接到ESP32的GPIO 16(數(shù)據(jù)/命令選擇)。
TFT_RST:連接到ESP32的GPIO 4(復(fù)位)。
#define TFT_MOSI 2 #define TFT_SCLK 15 #define TFT_CS 17 #define TFT_DC 16 #define TFT_RST 4
4. LED(狀態(tài)指示)
LED用于指示系統(tǒng)狀態(tài)。以下是其接線方法:
LED正極:連接到ESP32的GPIO 21。
LED負極:接地。
#define ledPin 21
5. 按鍵(用戶輸入)
按鍵用于用戶輸入操作。以下是其接線方法:
按鍵引腳:連接到ESP32的GPIO 18。
按鍵另一端:接地。
上拉電阻:在GPIO 18和3.3V之間接一個10kΩ的上拉電阻。
#define keyPin 18
八、硬件連接圖
以下是硬件連接的示意圖:
ESP32 GPIO 25 (I2S_DOUT) -> MAX98357 DIN
ESP32 GPIO 27 (I2S_BCLK) -> MAX98357 BCLK
ESP32 GPIO 26 (I2S_LRC) -> MAX98357 LRC
MAX98357 SPK+/- -> 喇叭
ESP32 GPIO 32 (I2S_WS) -> INMP441 WS
ESP32 GPIO 35 (I2S_SD) -> INMP441 SD
ESP32 GPIO 33 (I2S_SCK) -> INMP441 SCK
INMP441 L/R -> GND
ESP32 GPIO 2 (TFT_MOSI) -> TFT MOSI
ESP32 GPIO 15 (TFT_SCLK) -> TFT SCK
ESP32 GPIO 17 (TFT_CS) -> TFT CS
ESP32 GPIO 16 (TFT_DC) -> TFT DC
ESP32 GPIO 4 (TFT_RST) -> TFT RST
ESP32 GPIO 21 (ledPin) -> LED正極
LED負極 -> GND
ESP32 GPIO 18 (keyPin) -> 按鍵引腳
按鍵另一端 -> GND
ESP32 GPIO 18 -> 10kΩ上拉電阻 -> 3.3V
九、開始測試
1. 硬件準備
確保以下硬件已正確連接:
ESP32開發(fā)板:主控芯片。
MAX98357音頻放大器:連接喇叭,用于語音輸出。
INMP441麥克風(fēng):用于語音輸入。
TFT屏幕:顯示交互信息。
LED:用于狀態(tài)指示。
按鍵:用于觸發(fā)語音輸入。
2. 上電啟動
將ESP32開發(fā)板連接到電源,系統(tǒng)會自動啟動并初始化所有硬件。TFT屏幕會顯示歡迎信息,LED會亮起表示系統(tǒng)已就緒。
十、交互流程
1. 按住按鈕開始說話
操作:按住按鍵(GPIO 18)。
提示:TFT屏幕會顯示“聆聽中...”,LED會閃爍表示正在錄音。
錄音:系統(tǒng)通過INMP441麥克風(fēng)采集語音數(shù)據(jù)。
2. 釋放按鈕結(jié)束錄音
操作:釋放按鍵。
提示:TFT屏幕會顯示“思考中...”,LED保持常亮。
處理:系統(tǒng)將采集到的語音數(shù)據(jù)上傳至百度智能云進行語音識別。
3. 獲取語音識別結(jié)果
操作:等待系統(tǒng)處理。
提示:TFT屏幕會顯示識別結(jié)果(例如“你說:你好”)。
處理:系統(tǒng)將識別結(jié)果發(fā)送至KIMI API,獲取AI生成的回復(fù)。
4. 播放語音回復(fù)
操作:系統(tǒng)自動播放語音回復(fù)。
提示:TFT屏幕會顯示回復(fù)內(nèi)容(例如“回復(fù):你好,我是智能機器人!”)。
播放:通過MAX98357音頻放大器驅(qū)動喇叭播放語音回復(fù)。
視頻展示: