Unity + Arduino 的組合是一個常見的架構。Unity 是一個遊戲引擎,使用 C# 語言來開發,能有效的使用 Serial Port 來和 Arduino 溝通。而 Arduino 能連接各種電路與晶片,再配合價格低廉的 MFRC522 RFID 讀取器與自行埋在道具之中的 RFID 標籤,就能用很低的成本來開發出實體互動裝置。
參考以下影片,開發者將 RFID 標籤藏在玩具車的下面。當玩具車被放置在 RFID 讀取器上 (紅色框),Unity 就會生成對應玩具車的物件。我們能透過這個觀念,配合實體道具來設計互動系統,能強化使用者對於實體道具和虛擬元素之間的聯想。例如:用滑鼠在遊戲內開槍 vs. 拿實體槍來在遊戲內開槍,這之間的體驗感受就差很多了!
本文將說明如何使用 Unity 與 Arduino 來用 RFID 開發實體道具的互動功能,我們會使用到 MFRC522 晶片、MFRC522 支援的感應標籤 (13.56MHz) 與 Arduino Uno 主機板。
建立 RFID 讀取功能
Arduino 與 RFID 晶片之間需使用電線來連接,於連接後才能透過電腦上的 Arduino IDE 來燒錄 RFID 程式。
連接 Arduino + RFID
我們使用 MFRC522 晶片來作為 RFID 的讀取器,全新的 MFRC522 晶片會附帶排針,開發者需要自行將排針焊接到晶片上,才能用杜邦公母線來連接。由於 MFRC522 需要連接的線路很多,再加上杜邦線很常出現接觸不良或斷路的問題,建議在連接完畢後拿三用電表來測一下每個線路是否有接通。直接使用杜邦線連接 Arduino Uno 與 MFRC522 後的狀態會長這樣:
MFRC522 各個針腳對應到 Arduino Uno 的針腳編號如下表,MFRC522 的針腳名稱有印在接口旁邊,Arduino Uno 的針腳編號皆為數位腳位。
MFRC522 針腳 | Arduino Uno 針腳 |
---|---|
SDA | 10 |
SCK | 13 |
MOSI | 11 |
MISO | 12 |
IRQ | 不用連接 |
GND | GND |
RST | 9 |
3.3V | 3.3V |
連接後的電路圖如下,請注意電壓為 3.3V,Arduino 的 9 ~ 13 腳位都需連接。
Arduino Uno 與 MFRC522 晶片接線示意圖 (圖片來源:Electronic Clinic)
安裝 MFRC522 模組
接下來請將 Arduino 連接到電腦,並啟動 Arduino IDE (需安裝),展開頂部選單查看已連接的裝置,請從列表中選擇被辨識為 Arduino Uno 的硬體。有些 Uno 主機板可能不會被辨識到,這時請嘗試選擇除了 COM1 以外的選項,直到連接成功。本文使用的是「COM7」。
為了讓 IDE 能存取 RFID 晶片,請從左側的選項中進入 Library Manager,搜尋「mfrc522」後安裝由 Github Community 開發的 MFRC522 模組。
燒錄 RFID 讀取程式
Arduino 需要燒錄程式後才能讀取 RFID 的資訊,請從頂部選單選擇 File > Examples > MFRC522,選擇「ReadNUID」來開啟模組作者提供的讀取程式。這時會新開一個 Arduino IDE 的視窗,舊視窗的請直接關閉。
開啟 ReadNUID 後,請點擊左上角的燒錄按鈕,即可將程式燒錄進 Arduino。燒錄完成後,請點擊右上角來啟動 Serial Monitor,這時請拿 RFID 標籤靠近 MFRC522 晶片,Serial Monitor 會出現「In hex: …」與「In dec: …」的訊息,代表晶片有順利感應到 RFID 標籤的資訊。
本文使用的範例程式是用於偵測 RFID 標籤的「變化」,每次感應的標籤要不同。因此,如果我們重複感應同一個標籤,他會顯示「Card read previously.」,這是正常現象。
操作到這裡,我們已經完成 MFRC522 與 Arduino 之間的連接與通訊,接下來請關閉 Arduino IDE,下一步將開始操作 Unity 來整合 Arduino 與 RFID 功能。
整合 Unity 與 Arduino
Unity 需要透過 Serial Port 來和 Arduino 通訊,本文採用 Ardity 套件來開發 Unity 與 Arduino 溝通的功能。
安裝 Ardity 套件
請啟動 Unity 專案,從頂部選單的 Window 來打開 Package Manager,再展開視窗左上角的 +,選擇「Install package from git URL…」,再複製 Ardity 套件的連結來安裝。Unity 需要電腦安裝 Git 才能從 GitHub 上下載套件,安裝完成後請重新啟動電腦來生效。
我們修改 Ardity 原專案來讓它更好使用,請使用以下連結來安裝:
1https://github.com/tedliou/Ardity.git?path=Packages/ardity#2.0.1
接收 Arduino 訊息
Ardity 提供的 SerialController 能快速連接 Arduino,請點擊 Project 面板右上角的按鈕來顯示隱藏檔案,再展開 Packages 資料夾,拖曳 Ardity > Prefabs 下的 SerialController 到場景中。
選取 SerialController,請調整 Port Name 為先前連接 Arduino 用的名稱 (本文為 COM7),Baud Rate 為 9600,Max Unread Messages 為 10 (可調高一些,讓系統能一次接收更多訊息)。
接下來我們要寫一個程式來從 SerialController 接收 Arduino 的訊息,請建立一個空物件和附加在空物件的 C# 腳本,都命名為 ArduinoController。
我們要讓 SerialController 將 Arduino 訊息傳到 ArduinoController,請再一次選取 SerialController,拖曳 ArduinoController 空物件到 Message Listener 欄位。
編輯 ArduinoController 腳本,建立 OnConnectionEvent 與 OnMessageArrived 方法,用來接收 SerialController 輸入的訊息。
1using UnityEngine;
2
3public class ArduinoController : MonoBehaviour
4{
5 private void OnConnectionEvent(bool state)
6 {
7 Debug.Log($"連線狀態:{state}");
8 }
9
10 private void OnMessageArrived(string msg)
11 {
12 Debug.Log($"接收資料:{msg}");
13 }
14}
執行 Unity 專案,這時 SerialController 會連線到 Arduino,並開始接收 MFRC522 的辨識結果。拿 RFID 標籤靠近 MFRC522 晶片,Console 面板會顯示 Unity 接收到的訊息。
讀取 RFID 標籤編號
本文辨識開頭為「In Hex:」開頭的字串,並擷取後面的 16 進位 RFID 標籤編號,用來辨識各個標籤的差異。使用 String 的 StartsWith 方法來過濾字串開頭,再用 Substring 擷取 RFID 編號,最後用 Replace 刪除編號中的所有空白字元。
1using UnityEngine;
2
3public class ArduinoController : MonoBehaviour
4{
5 private void OnConnectionEvent(bool state)
6 {
7 Debug.Log($"連線狀態:{state}");
8 }
9
10 private void OnMessageArrived(string msg)
11 {
12 Debug.Log($"接收資料:{msg}");
13
14 if (msg.StartsWith("In hex:"))
15 {
16 var hex = msg.Substring(7).Replace(" ", "");
17 Debug.Log($"辨識結果:{hex}");
18 }
19 }
20}
再次執行 Unity 專案,感應 RFID 標籤後,Console 面板即可顯示格式化的標籤編號。
分類 RFID 標籤編號
本文的目標是感應 3 個 RFID 標籤時,系統能根據感應到的標籤編號來分類,轉換成「選項 A」、「選項 B」與「選項 C」。請編輯 ArduinoController,使用 switch 語法根據 RFID 標籤編號來分類,並將分類結果儲存到靜態變數「option」。
1using UnityEngine;
2
3public class ArduinoController : MonoBehaviour
4{
5 public static string option = "無選項";
6
7 private void OnConnectionEvent(bool state)
8 {
9 Debug.Log($"連線狀態:{state}");
10 }
11
12 private void OnMessageArrived(string msg)
13 {
14 Debug.Log($"接收資料:{msg}");
15
16 if (msg.StartsWith("In hex:"))
17 {
18 var hex = msg.Substring(7).Replace(" ", "");
19 Debug.Log($"辨識結果:{hex}");
20
21 switch (hex)
22 {
23 case "43223319":
24 option = "選項 A";
25 break;
26 case "7325A11A":
27 option = "選項 B";
28 break;
29 case "B365A11A":
30 option = "選項 C";
31 break;
32 }
33
34 Debug.Log($"選項切換:{option}");
35 }
36 }
37}
執行 Unity 專案,感應到 RFID 標籤後,Console 面板將會顯示分類後的選項名稱。
至此,我們已經完成 Unity 與 Arduino 之間的通訊,也能從 Arduino 傳入的訊息中讀取 RFID 標籤的編號,並取一個名稱來做分類,最後本文將透過設計一個簡單的互動「變色球」來進行應用。
設計互動功能
人的「互動」、系統的「處理」與產生的「回饋」是人機互動的基礎,我們讓使用者拿 RFID 標籤來感應 MFRC522,Arduino 讀取 MFRC522 獲得的感應資料,Unity 再讀取、分類 Arduino 的訊息。目前已完成「互動」和「處理」的功能,現在我們要使用 Unity 來設計一個簡單的「回饋」,當使用者感應 RFID 標籤時,畫面上的球體會變成相應的顏色。
請在場景上建立一個命名為 Ball 的球體,再建立 BallController 腳本並附加到 Ball 上。
接下來要開發球的變色功能,請編輯 BallController,讓系統偵測到 ArduinoController 的 RFID 分類結果 option 發生變化時,會根據分類的選項 A ~ C 來改變 Ball 的顏色,A、B、C 分別對應於藍色、紅色、黃色。如果是系統剛啟動、option 是初始值「無選項」的話,Ball 會變成白色。
1using UnityEngine;
2
3public class BallController : MonoBehaviour
4{
5 private string _lastOption;
6
7 private void Update()
8 {
9 if (_lastOption == ArduinoController.option)
10 return;
11
12 _lastOption = ArduinoController.option;
13 var mat = GetComponent<MeshRenderer>().material;
14
15 switch (_lastOption)
16 {
17 case "無選項":
18 mat.color = Color.white;
19 break;
20 case "選項 A":
21 mat.color = Color.blue;
22 break;
23 case "選項 B":
24 mat.color = Color.red;
25 break;
26 case "選項 C":
27 mat.color = Color.yellow;
28 break;
29 }
30 }
31}
最後執行 Unity 專案,感應不同的 RFID 標籤後,球體將會根據感應後的分類來即時改變顏色。