衆所周知,掌控板在創客教育中用的非常廣泛,它是一塊基於 ESP32 的學習開發板。大家對掌控板編程,用的比較多的都是圖形化編程的方式,比如 mPython、Mind+ 等。但是,既然掌控板是基於 ESP32 芯片的,所以我們也可以用 Arduino 軟件對其編程。所以,有時間的話,我準備給大家分享一系列用 Arduino 代碼對掌控板(ESP32)編程的教程:用Arduino玩轉ESP32與掌控板系列
本系列歷史文章目錄:
本期給大家帶來的是掌控板 Siri 語音識別的第 2 篇:如何通過 Siri 語音識別獲取傳感器數據。
掌控板 Siri 語音識別的第 1 篇跳轉:Siri 語音識別控制 LED 燈
國際慣例,先來看一下演示效果吧。點擊下方鏈接跳轉 B 站觀看演示視頻:
https://www.bilibili.com/video/av98141978/
項目概述
在上一篇中,我向大家詳細展示瞭如何利用 Siri 控制掌控板和 LED 燈,這一篇是上一篇的進階,我將繼續教大家如何用 Siri 去讀取各種傳感器的數據。
沒看過上一篇的朋友,建議先去看一下第 1 篇的內容。
跳轉鏈接:掌控板 Siri 語音識別的第 1 篇:LED 燈控制
這次主控板選擇的仍然是掌控板,當然正如我前面篇章所說的,你也可以選擇其他 ESP32 或者 ESP8266 系列開發板,實現的方法和效果是類似的。讀取的傳感器數據包括掌控板自帶的聲音傳感器、光線傳感器、以及外接的 DHT11 溫溼度傳感器,學習了本篇章之後,希望你可以學會修改相應代碼,換成其他傳感器。
在這個項目中,我們同樣將掌控板 ESP32 設置爲一個 Web 服務器,當用戶在網頁上訪問這個服務器的域名地址(或 IP 地址)的時候,就會跳轉到如下界面。最終實現的效果是,不僅可以用 Siri 語音識別去獲取傳感器數據,也可以直接在網頁端查看傳感器數據。
我們可以通過點擊 LED 的切換開關來控制掌控板上的 RGB LED 的亮滅,也可以訪問這個切換開關的對應域名地址,來控制 LED 燈的亮滅。
針對傳感器,我們可以直接在網頁上一次性讀取所有傳感器的數據,也可以單獨訪問每個傳感器對應的域名地址來讀取相應的數據。這樣就完成了基本的通過 Web 頁面控制掌控板以及讀取數據的功能。
在這基礎之後,我們可以通過設置一些語音助手,比如 Siri、天貓語音精靈等,通過語音命令訪問對應的域名地址,從而實現語音識別開關燈、讀取傳感器數據的功能。
電路連接
本項目中,我們需要外接一個 DHT11 溫溼度傳感器,通過擴展板將它接在掌控板 P0 引腳,如下圖所示。聲音數據和光線數據,直接通過掌控板賬面自帶的兩個傳感器讀取即可。
庫文件安裝
這個項目需要用到 4 個 Arduino 庫:除了上一篇章用到的 Adafruit_NeoPixel、ESPAsyncWebServer、AsyncTCP 之外,我們還加入了 DHT 函數庫,它的功能主要是讀取 DHT11 溫溼度傳感器的數值。。
Arduino 庫安裝的教程不是本篇的重點,這裏不再贅述,只給出 4 個庫的網址,大家可以自行百度查找 Arduino 怎麼安裝庫。
- Adafruit_NeoPixel:https://github.com/adafruit/Adafruit_NeoPixel
- ESPAsyncWebServer:https://github.com/me-no-dev/ESPAsyncWebServer
- AsyncTCP:https://github.com/me-no-dev/AsyncTCP
- DHT:https://github.com/adafruit/DHT-sensor-library
Arduino 代碼
這一篇章的代碼是在上一篇章的基礎之上進行修改的,所以基礎部分不再贅述,只講解不同與添加部分。
頭文件及初始化定義
在程序的開頭,我們首先引入了需要用到的庫函數:
#include "WiFi.h"
#include "ESPAsyncWebServer.h"
#include "Adafruit_NeoPixel.h"
#include "Adafruit_Sensor.h"
#include "DHT.h"
然後設置網絡的賬號和密碼:
const char *ssid = "wifi_name";
const char *password = "wifi_password";
接着定義一些傳感器與執行器引腳,並對他們進行一些初始化設置:
#define SOUNDPIN 36 // P10
#define LIGHTPIN 39 // P4
#define LEDPIN 17 // P7
#define DHTPIN 33 // P0
接着定義了 DHT 對象、NeoPixel 對象(RGB LED 燈)和 WebServer 對象:
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);
Adafruit_NeoPixel pixels(3, LEDPIN, NEO_GRB + NEO_KHZ800);
AsyncWebServer server(80);
Web 頁面設計
然後是掌控板 Web 服務器的界面設計,界面設計使用的是 HTML 語言,這裏先放一個最基礎的界面設計。HTML 相關的代碼存儲在 index_html 變量中。
const char index_html[] PROGMEM = R"rawliteral(
// HTML code here
)rawliteral";
基礎的 HTML 頁面設計代碼如下:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style>
html {
font-family: "Microsoft Yahei";
text-align: center;
}
</style>
</head>
<body>
<h2>掌控板家庭數據中心</h2>
<a href="/led=on">Light On</a>
<p></p>
<a href="/led=off">Light Off</a>
<p>
<span>聲音:</span>
<span>%SOUND%</span>
</p>
<p>
<span>光線:</span>
<span>%LIGHT%</span>
</p>
<p>
<span>溫度:</span>
<span>%TEMPERATURE%</span>
<span>℃</span>
</p>
<p>
<span>溼度:</span>
<span>%HUMIDITY%</span>
<span>%</span>
</p>
</body>
</html>
這段代碼在網頁中顯示的效果如下。我們可以看到很多數據是在兩個百分號(%)之間的,比如 %SOUND%,這個是佔位符,我們在程序中讀取相應傳感器的數據之後,就可以自動替換了,程序中會有專門的函數程序去進行替換,這部分下面會講。
傳感器數據讀取函數
首先是讀取 DHT11 溫溼度傳感器的函數,這部分比較簡單,直接參考 DHT 函數庫例程就好:
String readDHTTemperature() {
float temperature = dht.readTemperature();
if (isnan(temperature)) {
Serial.println("Failed to read from DHT sensor!");
return "--";
}
else {
Serial.println(temperature);
return String(temperature);
}
}
String readDHTHumidity() {
float humidity = dht.readHumidity();
if (isnan(humidity)) {
Serial.println("Failed to read from DHT sensor!");
return "--";
}
else {
Serial.println(humidity);
return String(humidity);
}
}
然後是 processor() 函數,這個函數的功能主要就是將網頁部分的所有佔位符替換爲相應的傳感器數值。它可以根據佔位符的名稱,返回對應的數據。
// Replaces placeholder with sensor values
String processor(const String& var) {
if (var == "SOUND") {
return String(analogRead(SOUNDPIN));
}
if (var == "LIGHT") {
return String(analogRead(LIGHTPIN));
}
if (var == "TEMPERATURE") {
return readDHTTemperature();
}
if (var == "HUMIDITY") {
return readDHTHumidity();
}
return String();
}
setup()
在初始化函數 setup() 中,我們首先對串口、RGB 燈和 DHT11 傳感器進行了初始化:
Serial.begin(9600);
pixels.begin();
dht.begin();
然後將掌控板連接到網絡,並把 IP 地址在串口中打印出來:
// Connect to Wi-Fi
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED)
{
delay(1000);
Serial.println("Connecting to WiFi..");
}
Serial.println("WiFi connected");
// Print ESP32 Local IP Address and Some Tips
Serial.print("Open your brower, and visit: http://");
Serial.println(WiFi.localIP());
Serial.println();
最後就是最重要的 Web 服務器設置。關於 Web 服務器設置的詳細教程,可以查看官網:https://github.com/me-no-dev/ESPAsyncWebServer
這裏只放出本文需要的代碼。當訪問根目錄“/”時,會顯示所有的數據以及相關的控制按鈕。這裏顯示數據調用的就是上面講到的 processor 函數。
// Root / Webpage
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
request->send_P(200, "text/html", index_html, processor);
});
當訪問“/led=on”路徑時,設置 LED 燈爲亮;當訪問“/led=off”路徑時,設置 LED 燈爲滅。
// Webpage to turn on light
server.on("/led=on", HTTP_GET, [](AsyncWebServerRequest *request) {
pixels.setPixelColor(0, 0xFF0000);
pixels.setPixelColor(1, 0xFF0000);
pixels.setPixelColor(2, 0xFF0000);
pixels.show();
Serial.println("LED is on");
request->send_P(200, "text/plain", "led on");
});
// Webpage to turn off light
server.on("/led=off", HTTP_GET, [](AsyncWebServerRequest *request) {
pixels.setPixelColor(0, 0x000000);
pixels.setPixelColor(1, 0x000000);
pixels.setPixelColor(2, 0x000000);
pixels.show();
pixels.clear();
Serial.println("LED is off");
request->send_P(200, "text/plain", "led off");
});
然後當訪問每個傳感器相應路徑時,比如"/temperature"、"/humidity"、"/sound"、"/light"這些路徑,程序會調用相應的函數讀取傳感器數據,通過串口將數據打印出來,然後將它們轉化成文本 String 類型,並顯示在網頁上:
// Webpage to get the temperature value
server.on("/temperature", HTTP_GET, [](AsyncWebServerRequest *request) {
Serial.print("Temperature: ");
Serial.println(readDHTTemperature());
request->send_P(200, "text/plain", readDHTTemperature().c_str());
});
// Webpage to get the humidity value
server.on("/humidity", HTTP_GET, [](AsyncWebServerRequest *request) {
Serial.print("Humidity: ");
Serial.println(readDHTHumidity());
request->send_P(200, "text/plain", readDHTHumidity().c_str());
});
// Webpage to get the sound value
server.on("/sound", HTTP_GET, [](AsyncWebServerRequest *request) {
Serial.print("Sound: ");
Serial.println(analogRead(SOUNDPIN));
request->send_P(200, "text/plain", String(analogRead(SOUNDPIN)).c_str());
});
// Webpage to get the light value
server.on("/light", HTTP_GET, [](AsyncWebServerRequest *request) {
Serial.print("Light: ");
Serial.println(analogRead(LIGHTPIN));
request->send_P(200, "text/plain", String(analogRead(LIGHTPIN)).c_str());
});
在 setup() 函數的最後,運行 Web 服務器:
server.begin();
至此,整個程序就編寫完成了,在 loop() 函數中,不需要做任何事,當然你也可以運行其他你想要的代碼。
程序上傳
在 Arduino 中選擇掌控板或者 ESP32 相關的芯片,然後將程序上傳,打開串口監視器,我們可以看到串口監視器中提示我們訪問相應的網址。(如果沒看到相應信息,可以按一下掌控板後面的 RST 按鍵,重啓程序)
打開電腦瀏覽器或者手機瀏覽器,訪問相應的 IP 地址,這裏是:192.168.10.202,我們可以看到網頁上顯示了相應的信息。
嘗試訪問對應的地址,當訪問 192.168.10.202/led=on 時,瀏覽器和串口監視器中,都輸出了相應的提示信息,同時我們也可以看到掌控板上的 RGB 燈也亮了起來。當訪問 192.168.10.202/led=off 時,瀏覽器和串口監視器中,也都輸出了相應的提示信息,同時掌控板上的 RGB 燈也熄滅了。
當訪問 192.168.10.202/sound 以及其他傳感器對應的網址是,瀏覽器和串口監視器中,也都輸出了相應的提示信息,如下圖所示。
網頁設計
這部分不是本文的重點,也不會影響最終語音控制的效果,所以如果您對網頁設計不感興趣,也可以略過,直接跳轉到下一節。
在上文中,我們已經基本完成了通過網頁來控制 LED 燈、以及讀取傳感器數據的相關功能,但是這個網頁畢竟還是太簡陋了。所以我們對網頁稍微進行一些優化。
具體 HTML 優化代碼請下載附件,這部分參考了國外大神的網站:https://randomnerdtutorials.com/
上述代碼最終形成的效果如下。
語音助手設置
接下來就是語音識別的設置,原理與上一篇 Siri 教程類似。由於筆者手上沒有其他語音助手或者智能音箱類產品,所以這裏還是以 Siri 爲例。
打開 iOS 系統自帶的捷徑 App(英文名稱 Shortcuts),沒有沒有的話,也可以去 App Store 免費下載:
快捷指令設置如下圖所示。捷徑的設置原理很簡單,就是訪問給定的 URL 地址。
由於 iPhone 中的捷徑是支持 Siri 語音識別調用的,所以我們可以直接通過 Siri 來運行這個捷徑,從而達到語音識別獲取傳感器數據的效果。
如果不知道怎麼設置快捷指令的話,也可以直接下載筆者的指令。複製下面的鏈接到 iPhone 瀏覽器中,就會提示你將這個指令添加到手機中。
https://www.icloud.com/shortcuts/4e20f185da76479a90f0716c9521cc7a
效果演示
喚醒你的 Siri 看看效果吧。不過這裏需要注意的是,你的 iPhone 和掌控板,必須處於同一局域網中。
總結
在本章中,我們學習了:
- 進一步學習了 WebServer 的基礎用法;
- 然後通過設計 HTML 網頁代碼,讓交互界面更加友好方便;
- 最後通過 iOS 的捷徑應用,實現了語音識別獲取傳感器數據的功能
相比上一篇 Siri 控制 LED 燈的內容,如果不考慮網頁設計相關內容的話,其實 Arduino 代碼端基本是類似的,希望讀者可以學會擴展。
如果本文對你有幫助的話,點個贊支持一下嘍。
代碼下載
點擊下方鏈接,查看完整代碼下載地址: