Unity + Arduino:用 RFID 開發實體道具辨識的互動功能

Ted Liou 2025.06.10 實體介面 最後更新 2026.03.17

快速摘要

RFID 很適合拿來做實體道具辨識。本文以 Arduino Uno、MFRC522 與 Unity 為例,示範如何把標籤 UID 轉成乾淨的序列資料,再在 Unity 裡分類成互動選項,完成一個可直接延伸的實體互動骨架。

RFID 很適合拿來做實體道具辨識。只要把標籤藏進卡片、玩具、模型或控制物件裡,Unity 就能根據讀到的 UID 切換內容,讓「拿起哪個道具」直接變成系統輸入。這種做法在展示互動、教育裝置、體感遊戲和展場體驗都很好用,因為它比純螢幕按鈕更有物件感。

但這裡有個界線要先講清楚。本文談的是互動辨識,不是安全驗證。截至 2026 年 3 月,目前維護中的 Arduino_MFRC522v2 README 仍明確提醒:卡片 UID 不能當成安全專案的唯一識別值。這套做法很適合分辨「這是哪一個道具」,不適合拿去做門禁、支付或其他安全用途。請參考:Arduino_MFRC522v2 READMENXP MFRC522 Datasheet

先看一下這種互動大概會長成什麼樣子。影片裡的概念很直觀:把 RFID 標籤藏進實體物件裡,讀到哪個標籤,Unity 就切到對應的內容。真正的重點,在於它把虛擬系統和實體道具之間的關係講得很清楚。

先把硬體連接穩定下來

本文以 Arduino Uno、MFRC522 讀卡模組與 13.56 MHz 標籤為例。MFRC522 這一代模組便宜、常見,也很適合教學和快速原型,但它對供電和接線品質比很多人想像中更敏感。

官方維護庫在 README 裡也明講了兩件事。第一,市面上的 MFRC522 模組品質差異很大,買到焊接或元件品質不好的板子並不稀奇。第二,SPI 不喜歡太長、太鬆的線路。這兩件事其實就是為什麼有些專案看起來一切照表操課,讀卡卻還是斷斷續續。

我自己的建議很務實:先把線接短、供電確認在 3.3V、排針焊好,再開始懷疑程式碼。很多問題根本不是程式。

連接 Arduino Uno 與 MFRC522

MFRC522 和 Arduino Uno 之間走的是 SPI。依照目前維護庫 README 的 pin layout,常見接法如下:

MFRC522 針腳Arduino Uno 針腳
SDA10
SCK13
MOSI11
MISO12
IRQ不用連接
GNDGND
RST9
3.3V3.3V

接好之後,實體狀態大概會像這樣。若你用的是杜邦線,我會建議順手拿三用電表量一下導通,尤其是第一次做硬體整合時,這比盯著程式碼找錯還省時間。

Arduino Uno 與 MFRC522 以杜邦線連接後的實際照片

下面這張圖可以幫我們再對一次接腳位置。本文不使用 IRQ,也不碰多讀卡器配置,先把單一讀卡器讀穩就好。

Arduino Uno 與 MFRC522 的 SPI 接線示意圖 Arduino Uno 與 MFRC522 接線示意圖。圖片來源請參考:Arduino_MFRC522v2 pin layout

安裝 MFRC522 套件並驗證硬體

請在 Arduino IDE 的 Library Manager 搜尋 mfrc522,安裝目前維護中的 Arduino_MFRC522v2。它支援 Arduino 內建的 Library Manager,也比舊文章常見的歷史版本更接近現在還在維護的狀態。

Arduino IDE 透過 Library Manager 搜尋 mfrc522 相關套件的畫面

裝好後,我建議先不要急著串 Unity,先用套件內建的 DumpInfo 範例確認讀卡器、供電和標籤都正常。只要 Serial Monitor 能穩定看到 UID 與卡片資訊,代表硬體這一段大致沒問題。若這一步就不穩,先回頭檢查供電、接線長度、焊點與模組品質。

不解析範例輸出,直接輸出自己的 UID 格式

很多教學會直接去解析範例輸出的 In hex: 或整串 debug 訊息。這種做法在 Demo 還能用,但只要套件版本、範例名稱或輸出格式一變,Unity 端就要跟著修。

比較穩的方式,是我們自己寫一個只做一件事的 sketch:讀到標籤時,只輸出一行乾淨的 UID。

 1#include <MFRC522v2.h>
 2#include <MFRC522DriverSPI.h>
 3#include <MFRC522DriverPinSimple.h>
 4
 5MFRC522DriverPinSimple ssPin(10);
 6MFRC522DriverSPI driver{ssPin};
 7MFRC522 mfrc522{driver};
 8
 9void setup() {
10  Serial.begin(115200);
11  mfrc522.PCD_Init();
12}
13
14void loop() {
15  if (!mfrc522.PICC_IsNewCardPresent() || !mfrc522.PICC_ReadCardSerial()) {
16    return;
17  }
18
19  for (byte i = 0; i < mfrc522.uid.size; i++) {
20    if (mfrc522.uid.uidByte[i] < 0x10) {
21      Serial.print('0');
22    }
23    Serial.print(mfrc522.uid.uidByte[i], HEX);
24  }
25  Serial.println();
26
27  mfrc522.PICC_HaltA();
28  mfrc522.PCD_StopCrypto1();
29  delay(200);
30}

這段程式做的事情很單純。讀到新卡時,把 UID 逐 byte 轉成十六進位,補齊前導零,最後送出一行字串。Unity 端之後只需要接收像 43223319 這樣的值,不用再去猜哪一段是標題、哪一段是空白、哪一段才是系統真正要用的資料。

接下來請把程式燒錄進 Arduino,並用 Serial Monitor 確認感應標籤時能穩定輸出 UID。確認完成後,把 Arduino IDE 關掉。因為只要 Serial Monitor 還佔住 Port,Unity 端通常就接不上。

Unity 端只接 UID,不接示範訊息

Unity 這一段我仍然使用 Ardity 來處理 Serial 通訊。它把 Serial 連線、背景執行緒和訊息接收包成可以直接用的元件,對這種文章示範很省時間。

安裝 Ardity 套件

打開 Unity 的 Package Manager,選擇「Install package from git URL…」,貼上下列位址:

1https://github.com/tedliou/Ardity.git?path=Packages/ardity#2.0.1

這個 tag 目前仍存在。若 Unity 跳出 API Compatibility Level 不支援的訊息,直接依 Ardity 套件內建檢查器的建議處理即可。

Unity 透過 Git URL 安裝 Ardity 套件的 Package Manager 畫面

安裝後,把 SerialController 拖到場景中,設定對應的 Port NameBaud Rate。本文 Arduino 端改成 115200,Unity 端也要跟著一致。

Unity 場景中加入 Ardity 的 SerialController 並設定序列埠參數

接收 UID 並分類成互動選項

接收端我們不再解析 In hex:,而是直接讀一行 UID。建立一個空物件 ArduinoController,再掛上下面這支腳本:

 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        var uid = msg.Trim().ToUpperInvariant();
15        if (string.IsNullOrEmpty(uid))
16            return;
17
18        Debug.Log($"辨識結果:{uid}");
19
20        switch (uid)
21        {
22            case "43223319":
23                option = "選項 A";
24                break;
25            case "7325A11A":
26                option = "選項 B";
27                break;
28            case "B365A11A":
29                option = "選項 C";
30                break;
31            default:
32                option = "無選項";
33                break;
34        }
35
36        Debug.Log($"選項切換:{option}");
37    }
38}

這裡多做了兩件小事。第一個是 Trim(),把 Serial 殘留的換行和空白清掉。第二個是 ToUpperInvariant(),把格式統一成大寫,這樣 Arduino 端和 Unity 端不會因為大小寫不一致而失配。

再來把 ArduinoController 指定給 SerialControllerMessage Listener。從這裡開始,RFID 的角色就很清楚了:它提供的是一個穩定的「道具是哪個」的輸入訊號。

Unity 中建立 ArduinoController 物件與腳本的畫面

把 ArduinoController 拖進 SerialController 的 Message Listener 欄位

當不同 UID 被分類成不同選項後,Console 會開始出現比較像系統內部邏輯的訊息,而不是一整串硬體 debug 字串。

Unity Console 顯示 RFID UID 被分類成系統內部選項名稱的畫面

把 RFID 選項接到可見的互動回饋

只有 Console 會變,其實還不算互動。我們還需要把這個分類結果真的接到場景裡的東西。

這裡用最簡單的例子就夠了:建立一顆球,讓它根據 RFID 標籤切換顏色。這類做法雖然簡單,但它已經把整個實體互動的骨架都建好了。之後想換成切換角色、切換影片、切換場景狀態,方法都一樣。

先在場景中建立一個球體 Ball,並掛上 BallController

Unity 場景中的球體物件已掛上 BallController 腳本

BallController 如下:

 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}

這支腳本幾乎沒有多餘邏輯。它只關心 ArduinoController.option 有沒有變,變了就更新顏色。互動規模還小的時候,這種分工已經夠清楚,也很適合之後再擴充成更大的系統。

最後執行 Unity,感應不同 RFID 標籤後,球體就會跟著切換顏色。

感應不同 RFID 標籤後,Unity 場景中的球體即時改變顏色

總結

RFID 很適合拿來做實體道具辨識,因為它能把「拿了什麼物件」變成一個很乾淨的系統輸入。這篇做的事情其實很單純:先把 MFRC522 讀卡穩定下來,再把 UID 輸出成乾淨的一行字串,最後讓 Unity 根據 UID 分類出互動選項。只要這條骨架先站穩,後面不管是換成切換場景、切換內容,或接到更完整的互動流程,都會很順。

常見問題

不建議。本文這套做法適合用在互動道具辨識,不適合門禁、支付或其他安全用途。官方維護庫也明確提醒 UID 可能被複製,安全相關專案需要額外的驗證機制。

因為範例輸出主要是給人看,不是給系統接。實際專案比較穩的做法,是自己輸出乾淨的 UID 字串,Unity 端就不用綁在某個示範範例的字面格式上。

先檢查序列埠是不是被 Arduino IDE 佔住了。只要 Serial Monitor 還開著,Unity 通常就拿不到同一個 Port。再來才是檢查 Port Name、Baud Rate 與接線。

作者

Ted Liou

現職 Unity C# 工程師,主要分享 Unity、C# 與 Vibe Coding 相關技術教學。

上一篇 StreamDiffusion:用 OSC 控制提示詞,並以 NDI 傳送即時影像 下一篇 Unity 6 VS Code 設定:修正 C# 自動完成失效與專案同步