【ESP32專欄】ESP32藍芽連線 — 即時通訊與語音指令

作者:尤濬哲

藍芽與 WiFi 都是用來通訊的,藍芽通常用於近端點對點通訊,所謂的點對點就像是藍芽無線耳機與手機連接,用來播放音樂,又如藍芽滑鼠鍵盤功能是輸入文字,它只是一種序列通訊,功能較為簡單,而 WiFi 則常用來連入網際網路,相比之下 WiFi 需要比較複雜的設定,而藍芽只需配對就能取用服務。

與藍芽同位階的應該算是紅外線,不過紅外線有方向性,必須對準裝置才能傳輸,其速度慢不說,距離大概不能超過 10 公尺,而藍芽無方向性,因此不用對準,且傳輸距離遠,速度也比紅外線快很多。

本章先簡介 ESP32 的藍牙通訊設定與使用,由於它是藍芽內建的,所以不用接線或設定 AT COMMAND,也不用宣告 TXRX 相關的通訊協定,值得一提的是,而且它屬於低功率藍芽(BLE:Bluetooth Low Energy),耗電量較少外,傳輸距離理論可達 300 公尺遠,實際測試 30 公尺也沒問題,相對常見搭配 UNO 使用的 HC-05 屬於藍芽 2.1,理論傳輸距離只有 10 公尺。

藍芽單向傳輸

這邊會說明如何使用 ESP32 藍芽將資訊傳遞給藍芽裝置(手機)進行接收,另由於 bluetooth 函式庫與 iOS 手機不相容的原因,接下來都將使用 Android 裝置進行解說。

ESP32 藍芽的開啟僅需幾個步驟:

  1. 使用藍芽函式庫:#include <BluetoothSerial.h>
  2. 宣告藍芽序列通訊物件:BluetoothSerial BT;//BT 為藍芽通訊物件
  3. 在 Setup 中開啟藍芽:BT.begin(“BTName”);// BTName 為藍芽廣播名稱
  4. 當要傳輸資訊時:BT.print(“要傳輸的文字”);//println 則是換行

我們先來做一個簡單的測試,就是每秒傳輸一次「Hello World!」到手機中,程式如下:

#include <BluetoothSerial.h>
BluetoothSerial BT;//宣告藍芽物件,名稱為BT

void setup() {
Serial.begin(115200);
BT.begin("Eric1030");//請改名例如英文+生日,以免與其他同學名稱重複
}
 
void loop() {
  BT.println("Hello World!");
  delay(1000);
}

完成程式上傳後,我們來處理手機的部份,請開啟 Android 手機的 App store,並搜尋 Arduino Bluetooth Control,其圖示如下,APP Store 有很多類似的 APP,功能也都差不多,但是我們選定的這個 APP 有提供語音辨識的功能;若無法找到該 APP,可能是版本不相容,但可以從我的雲端空間下載備份 APK 檔案。

Arduino Bluetooth Control(圖片來源:Google Play

手機安裝好 APP 後,啟動藍芽連線設定,如果未在「可用裝置」中出現,請點選「不常用類型裝置」。

開啟藍芽設定(圖片來源:尤濬哲提供)

您就會看到您所設定的 ESP32 藍芽名稱,接著點選您的 ESP 裝置。

藍芽不常用裝置列表(圖片來源:尤濬哲提供)

接著會出現配對訊息,點選下方的配對即可完成配對。

開始配對(圖片來源:尤濬哲提供)

完成配對後,開啟剛剛安裝的 Arduino Bluetooth Control APP,如果沒有自動連線,請點選上方的箭頭圖示,選擇本次要連線的 ESP32 裝置。

開啟 APP 連線藍芽裝置(圖片來源:尤濬哲提供)

連線成功時,下方會出現「Connected to 裝置名稱」的訊息。

連線成功等候連線成功(圖片來源:尤濬哲提供)

此時再點選序列通訊的功能,即可看到每秒一次的「Hello World!」訊息。

點選右上序列通訊功能(圖片來源:尤濬哲提供)

觀察傳入的資訊(圖片來源:尤濬哲提供)

接下來我們將使用 DHT11 溫濕度計為範例,將溫濕度的值傳入手機中,另外記得每次 ESP32 更新程式重新啟動時,都必須按一下連線的圖示 ,重新與裝置建立連線,才能讀取資訊。

#include <SimpleDHT.h>
#include <BluetoothSerial.h>
BluetoothSerial BT;
int pinDHT11 = 25; //本例請將溫度計S腳接在左11 (GPIO25)
SimpleDHT11 dht11(pinDHT11);

void setup() {
  Serial.begin(115200);
  BT.begin("Eric1030");//請改名
}


 
void loop() {
  // start working...
  Serial.println("=================================");
  Serial.println("Sample DHT11...");
  // read without samples.
  byte temperature = 0;
  byte humidity = 0;
  int err = SimpleDHTErrSuccess;
  if ((err = dht11.read(&temperature, &humidity, NULL)) != SimpleDHTErrSuccess) {
    Serial.print("Read DHT11 failed, err="); Serial.println(err); delay(1000);
    return;
  }
  //將溫濕度傳輸到藍芽裝置
  BT.print((int)temperature);
  BT.print(" *C,");
  BT.print((int)humidity);
  BT.println(" H");
  delay(1000); //休息1秒
}

利用藍芽傳輸 DHT11 溫濕度(圖片來源:尤濬哲提供)

藍芽雙向傳輸

ESP32 能傳送資料到手機,那可以反過來讓手機傳資料到 ESP32 嗎?當然可以,而且更好玩!這部份 ESP32 的流程是:

1.檢測藍芽是否有資料:BT.available()
2.如果有資料,我們就把資料讀出:BT.readString()
3.將資料從電腦的序列視窗(Serial)中印出來

程式如下:

#include <BluetoothSerial.h>
BluetoothSerial BT;

void setup() {
  Serial.begin(115200);
  BT.begin("Eric1030");//請改名
}
void loop() {
  //檢查藍芽內是否有資料
  while (BT.available()) {
    //讀取藍芽資料
    String BTdata=BT.readString();
    //顯示在序列視窗
    Serial.println(BTdata);
  }
  delay(1);
}

連線成功後,一樣點選右上序列通訊功能後,在下方的空白處輸入文字並按鍵盤的 Done 或 Enter 送出,我們就能在電腦的序列通訊視窗中收到手機傳來的訊息。

在手機輸入訊息(圖片來源:尤濬哲提供)

ESP32 的序列視窗中讀取訊息(圖片來源:尤濬哲提供)

不過這樣單方面只有手機講話有點孤單,要怎麼讓 ESP32 也能打字回覆呢?其實語法很類似,只是與藍芽的方向相反,就是檢查序列是否有資料輸入 Serial.available();當 Serial.available() 用Serial.readString() 將資料讀入後,再用 BT.println() 將資料送到手機,不過 ESP32 要在哪裡打字呢?是透過序列通訊視窗上面的空白處,本部份程式如下:

#include <BluetoothSerial.h>
BluetoothSerial BT;

void setup() {
  Serial.begin(115200);
  BT.begin("Eric1030");//請改名
}

void loop() {
  //檢查序列內是否有資料
  while (Serial.available()) {
    //讀取序列資料
    String Sdata = Serial.readString();
    //傳輸給藍芽
    BT.println(Sdata);
  }


 
  //檢查藍芽內是否有資料
  while (BT.available()) {
    //讀取藍芽資料
    String BTdata = BT.readString();
    //顯示在序列視窗
    Serial.println(BTdata);
  }
  delay(1);
}

ESP32 在序列視窗輸入訊息(圖片來源:尤濬哲提供)

雙向資料傳輸(圖片來源:尤濬哲提供)

藍芽指令與語音辨識

這樣的程式只能用來藍芽聊天嗎?不,這其實已經足夠我們用來遙控一些東西囉!例如我們可以用簡單的 LED 燈測試,將 LED 依照前面的內容依序將綠黃紅放置在 GPIO 4,16,17(麵包板右 7,8,9)位置,接下來我們假設 ESP32 從藍芽接到傳來「1」時,就開啟綠 LED,而「2」代表關閉綠 LED,其餘雷同(「3」、「4」代表開啟及關閉黃 LED,「5」、「6」代表開啟及關閉紅 LED),這樣我們就可以用手機來遙控三個燈號了。完整程式如下:

#include <BluetoothSerial.h>
BluetoothSerial BT;

void setup() {
  Serial.begin(115200);
  BT.begin("Eric1030");//請改名
  pinMode(15, OUTPUT); //綠色LED
  pinMode(2, OUTPUT); //黃色LED
  pinMode(4, OUTPUT); //紅色LED
}

void loop() {
  //檢查序列內是否有資料
  while (Serial.available()) {
    //讀取序列資料
    String Sdata = Serial.readString();
    //傳輸給藍芽
    BT.print(Sdata);
  }


 
  //檢查藍芽內是否有資料
  while (BT.available()) {
    //讀取藍芽資料
    String BTdata = BT.readString();
    //顯示在序列視窗
    Serial.println(BTdata);
    //檢查藍芽資料及相對的指令
    if (BTdata == "1") {
      //1:開綠燈
      digitalWrite(15, HIGH);
    }
    if (BTdata == "2") {
      //2:關綠燈
      digitalWrite(15, LOW);
    }
    if (BTdata == "3") {
      //3:開黃燈
      digitalWrite(2, HIGH);
    }
    if (BTdata == "4") {
      //4:關綠燈
      digitalWrite(2, LOW);
    }
    if (BTdata == "5") {
      //5:開紅燈
      digitalWrite(4, HIGH);
    }
    if (BTdata == "6") {
      //6:關紅燈
      digitalWrite(4, LOW);
    }

  }
  delay(1);
}

我們將數字 1~6 按過一次,會發現燈號依序亮起熄滅,代表藍芽傳輸正常。

輸入數字 1-6,查看燈號變化(圖片來源:尤濬哲提供)

除了使用序列通訊用自己打字的方式外,也可以使用 APP 上的其他功能。

APP上的所有功能(圖片來源:尤濬哲提供)

我們先來看看左側上方的方向鍵,當我們點選不同方向時,會發現每個方向對應的都是一個數字(如圖17)

方向鍵功能(圖片來源:尤濬哲提供)

因此按下不同方向,剛好可以控制燈號,例如「^」對應數字「1」,所以按「^」就會開啟綠燈(在按鈕時,請記得慢慢按不要太急,否則它會將很多數字合成一個字串才送出,例如一直按往上「^」會送出「11111」,而我們的程式無法判讀這個東西,因為我們是用字串比對,而非字元比對)。

在加速器上,對應的方向與上面的方向鍵是相同的,不過它是透過手機的傾斜方向來控制送出訊號,例如你將手機向前傾斜一秒鐘後復原水平狀態,手機會對 ESP32 送出一連串的「11111111」,向後則會送出「2222222」等,但有些手機硬體沒有支援加速器,就不會送出任何資料;與上面相同的,我們的程式是以字串比對,所以這個功能無法控制燈號。

加速器功能(透過傾斜你的手機來觸發)(圖片來源:尤濬哲提供)

接收到的資料(圖片來源:尤濬哲提供)

按鈕的功能如下圖,不過這個 APP 有一個小 bug,就是 5、6 是標錯的,預設標成 4、4,因此我們要進入設定進行修改。

按鈕的功能(圖片來源:尤濬哲提供)

點選右上機器人圖示按鈕進入設定功能,尋找「Command button configuration」,點選 Button E,然後修改對應的值從 4 改為 5,相同的步驟,請設定 Button F 對應的值為 6,完成修改後,依序點選按鈕,也可以觀察到燈號的變化。

將 Button E 改為 5(圖片來源:尤濬哲提供)

最後是右下角的功能語音指令(Voice Control),也就是透過語音辨識來控制傳輸,不過我們必須先設定語音及所對應的文字,例如當我們說「開綠燈」,手機就送出「1」到 ESP32,而根據判斷 ESP32 獲得 1 就會開啟綠色 LED。

我們先點選右上角的機器人圖示來設定語音指令,進入設定後往下拉到底,可以找到「Vocal Command Configuration」的功能。

設定語音指令(圖片來源:尤濬哲提供)

進入設定畫面後,該 APP 一共提供 10 個語音指令。

一共有 10 組語音指令(圖片來源:尤濬哲提供)

設定方式如下,我們點選第一個語音指令「Vocal Command no 1」後,一共有兩個值要設定,第一個 Vocal command 代表要講的話,第二個 Data to send 則是要在藍芽發送的文字;舉例來說,要講的話就是「開綠燈」,而要在藍芽發送的文字則是「1」,這樣當手機聽到我們講「開綠燈」時,就會發送 1 到 ESP32,而依據程式的判斷,收到 1 就會開啟綠燈。

設定語音命令為「開綠燈」(圖片來源:尤濬哲提供)

設定要送出的文字「1」(圖片來源:尤濬哲提供)

其餘的語音指令則可以依照相同的方式設定,例如「Vocal Command no 2」的 Vocal command 設定為「關綠燈」、Data to send 設定為「2」,而「Vocal Command no 3」的 Vocal command 設定為「開黃燈」、Data to send 設定為「3」等。

接下來我們就可以利用手機語音辨識的功能來控制燈號開關。回到 APP 首頁畫面後,點選右下角的「Voice Control」語音按鈕就會跳出麥克風圖示,點選麥克風後,說出設定好的語音指令,例如「開綠燈」,在手機辨識「開綠燈」成功後,就會在藍芽送出「1」給 ESP32,ESP32 就會開啟綠燈。

點選右下角的 Voice Control(圖片來源:尤濬哲提供)

小結

本練習只運用 ESP32 的藍牙通訊來開啟或關閉 LED,是有點大材小用,但讀者可以自行開發新功能,例如透過繼電器來開啟或關閉電風扇、檯燈、冷氣等家電,達到簡易的智慧家電的功能,以下影片是之前做過的作品。

(本文經作者同意轉載自夜市小霸王部落格原文連結;責任編輯:賴佩萱)

尤濬哲

Author: 尤濬哲

身兼助理教授/專欄作家/知名部落客,以及點點滴滴科技研發總監等身份,專長包括人工智慧、多媒體互動(Unity)、智慧互動裝置(APP、Arduino)、虛擬實境與擴增實境互動、IoT 實做開發。 學歷:中山大學資訊管理研究所 博士

Share This Post On

Submit a Comment

Your email address will not be published. Required fields are marked *