用 Python 搭配 Firmata 控制 Arduino 腳位:適合快速做簡單 I/O

Ted Liou 2025.03.08 Python 最後更新 2026.03.17

快速摘要

如果需求只是從 Python 控制 Arduino 的腳位輸出、讀取簡單輸入,Firmata 會比自己重寫 Serial Protocol 省事很多。本文整理 StandardFirmata 的燒錄流程、pyFirmata2 的安裝方式,以及用 Python 控制 LED 腳位的基本做法,同時把這套方法不適合的情境講清楚。

如果需求只是從 Python 控制 Arduino 的數位輸出,或讀一些簡單的腳位狀態,Firmata 真的很省事。先把 Arduino 內建的 StandardFirmata 燒進去,再用 Python 端的 pyFirmata2 連線,很多原本要自己處理的 Serial 細節都可以先省掉。

這套做法的邊界也要先講清楚。請參考:Arduino 的內建範例文件pyFirmata2 專案頁。Firmata 適合腳位開關、LED、按鈕、磁簧這類簡單 I/O;如果你要接的是 RFID、客製通訊協定,或得在 Arduino 端做比較多即時邏輯,最後通常還是要回到自己寫 Arduino 韌體。本文走的,就是它最適合的那一條路。

什麼時候適合用 Firmata

我這次碰到的需求,是讓樹莓派接上一塊 Arduino UNO,從 Python 端去控制與偵測電路狀態。真正麻煩的地方不在腳位本身,而在「作業系統怎麼和 Arduino 穩定通訊」這件事。

如果我們自己從零開始設計序列埠協定,當然也不是不行,但光是封包格式、同步、例外處理就很容易把時間花掉。Firmata 的價值就在這裡:它先把 Arduino 與電腦之間的通訊協定包好了,讓我們把心力放在應用邏輯,而不是反覆除錯 Serial。

先把 StandardFirmata 燒進 Arduino

pyFirmata2 端假設 Arduino 已經跑著 Firmata 韌體,所以第一步先不是寫 Python,我們要先打開 Arduino IDE,載入內建的 StandardFirmata 範例。

請從 Arduino IDE 上方選單進入:

1File > Examples > Firmata > StandardFirmata

Arduino IDE 中的 StandardFirmata 內建範例位置

打開之後,不需要先改內容,直接把這份程式燒進 Arduino 就可以了。做到這一步,Arduino 端的準備其實就差不多完成。

Arduino IDE 中已打開的 StandardFirmata 專案

安裝 pyFirmata2

接下來回到 Python 端。本文以樹莓派為例,只要你手上有能安裝 pip 套件的 Python 3 環境即可,平台不限於樹莓派。

安裝指令很簡單:

1pip install pyFirmata2

pyFirmata2 的好處是把基本的 pin control、讀值和 callback 都整理得很順,對 Python 端來說,比自己直接啃原始序列埠舒服很多。

找出 Arduino 的序列埠名稱

雖然 pyFirmata2 支援自動偵測序列埠,但在 Linux 或樹莓派上,我還是建議先確認實際裝置名稱,後面排錯會省很多時間。

在還沒接 Arduino 之前,先在終端機執行:

1ls /dev/tty*

這時會列出一大串序列埠裝置。

尚未接上 Arduino 時,終端機列出的 /dev/tty* 裝置列表

接著把 Arduino 用 USB 接上樹莓派,再跑一次同樣的指令。通常會多出像 /dev/ttyACM0 這樣的新裝置;那個新出現的名稱,就是你後面要拿來連線的埠。

接上 Arduino 後,終端機中新增的 /dev/ttyACM0 裝置

如果你的環境換成 Windows,就會看到像 COM3COM4 這類名稱;macOS 常見的則會是 /dev/cu.usbmodem...。原理一樣,找出新出現的那一個就可以。

用 Python 控制 Arduino 腳位

這裡我用一個最單純、也最能驗證流程的例子:讓兩顆 LED 交替閃爍。電路接法如下:

  • 兩顆 LED 的正極分別接到 Arduino 的 12、13 腳位
  • 每顆 LED 串接一顆 1kΩ 電阻
  • 負極回到 GND

這種電路很單純,但剛好能把 Firmata 的基本輸出流程看清楚。

Arduino UNO 接兩顆 LED 的電路示意圖

程式也不複雜。把下面內容存成 main.py,再把 PORT 改成你剛才查到的序列埠名稱即可:

 1import time
 2
 3import pyfirmata2
 4
 5PORT = "/dev/ttyACM0"
 6board = pyfirmata2.Arduino(PORT)
 7
 8while True:
 9    board.digital[12].write(0)
10    board.digital[13].write(1)
11    time.sleep(1)
12
13    board.digital[12].write(1)
14    board.digital[13].write(0)
15    time.sleep(1)

這段程式的重點其實只有兩個:

  1. pyfirmata2.Arduino(PORT) 會建立 Python 與 Arduino 之間的連線。
  2. board.digital[x].write() 讓我們直接用 Python 控制指定腳位的高低電位。

如果你想偷懶,也可以改成 pyfirmata2.Arduino(pyfirmata2.Arduino.AUTODETECT) 讓它自動找埠。不過在有多塊板子、或偶爾會接不同 USB 裝置的環境下,我自己還是偏好把埠名寫清楚。

執行程式並確認結果

把檔案存好後,直接在終端機執行:

1python main.py

如果你是用 VS Code,也可以從右上角的執行按鈕直接跑。只要前面 StandardFirmata 已經燒好、序列埠名稱也填對,兩顆 LED 就會開始交替閃爍。

在 VS Code 中執行 Python 程式控制 Arduino 的畫面

實際效果如下:

做到這一步,其實就已經證明整條通路打通了。後面不管你要把這件事接到 Web API、資料庫、樹莓派上的背景服務,或做成更完整的互動裝置,基本骨架都一樣。

Firmata 不適合處理什麼

這點我想單獨拉出來講,因為很多人一看到「Python 可以直接控 Arduino」就會想一路往上疊功能。Firmata 很方便,但它不是萬用方案。

當需求開始碰到下面這些情境時,就要先停一下:

  • 感測器本身有複雜通訊協定,例如 RFID、某些 IMU、特殊序列裝置
  • Arduino 端需要自己做大量即時判斷
  • 資料交換量很大,或對時序要求特別敏感
  • 你已經明確知道要在 Arduino 端寫一套自己的邏輯

遇到這些需求時,讓 Arduino 自己負責裝置邏輯,Python 只收發整理好的資料,通常會比較穩。

總結

Firmata 最適合的場景,是快速把 Python 和 Arduino 接起來,先把簡單 I/O 做穩。如果我們的需求是控制 LED、讀按鈕、接磁簧開關,或把腳位狀態整合進既有的 Python 系統,這條路很省時間。

但只要需求一複雜,尤其是碰到特殊模組或即時控制,Firmata 的邊界就會很快浮出來。本文最後的判斷很簡單:它不是萬能,但在對的範圍內,確實很好用。

作者

Ted Liou

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

上一篇 Prism Launcher 是什麼?Minecraft 模組包下載、安裝與手動補檔教學 下一篇 移植標楷體到 macOS:解決 Word 字型不同與跑版問題