Python與Ardinio整合應用
Revised on September 28, 2019
 認識Firmata
 使用Firmata Test程式
 Python pyFirmata模組指令
 使用pyFirmata設計控制程式
 Python使用pySerial模組指令
 使用pySerial設計控制程式
 Firmata是⼀套通訊協定,用於微控制器板(如Arduino)和主機電腦
之間的溝通,藉由各種訊息來控制微控制器板腳位、以及從微控制器
板回報狀態
 既然是套協定,溝通兩端都必須實作,Arduino端可直接使用
Arduino IDE內建的Firmata範例程式;至於主機端的實作,有各種
程式語言的版本,Python語言的模組為pyFirmata
Firmata簡介
Python應用程式
pyFirmata
StandardFirmata
Firmata Communication
 載入StandardFirmata程式
 選單命令File> Examples> Firmata> StandardFirmata
 將程式燒錄到Arduino Uno板
燒錄StandardFirmata
StandardFirmata
 在Firmata官網(http://www.firmata.org/wiki/Main_Page)提供
⼀個測試程式,可透過序列埠與已燒錄StandardFirmata程式的
Arduino板連線,並測試Arduino IO
 下載Firmata Test
 http://www.pjrc.com/teensy/firmata_test/firmata_test.exe
 執行Firmata Test,選擇Arduino連線序列埠
使用Firmata測試程式 1/2
 D0與D1也是序列埠接腳,所以不能做為
⼀般IO
 D2~D13可設為
 Output 數位輸出
 Input 數位輸入
 PWM 輸出PWM信號
 Servo 輸出伺服馬達控制信號
 A0~A5可設為
 Output 數位輸出
 Input 數位輸入
 Analog 類比輸入
 Servo 輸出伺服馬達控制信號
使用Firmata測試程式 2/2
 安裝pyFirmata模組
 pip install pyfirmata
使用pyFirmata設計控制程式 1/6
 建立Arduino控制板物件
 Arduino控制板物件 = Arduino(port);
from pyfirmata import Arduino, util
from time import sleep
uno = Arduino('COM6')
sleep(3) #暫停一段時間讓pyFirmata和Arduino進行同步
 要讀取序列埠資料,必須開啟Iterator避免序列溢位
it = util.Iterator(uno)
it.start()
使用pyFirmata設計控制程式 2/6
 建立IO端點物件
 類比輸入端點 = Arduino控制板物件.get_pin('a:0:i') #A0腳位
 數位輸入端點 = Arduino控制板物件.get_pin('d:2:i') #D2腳位
 數位輸出端點 = Arduino控制板物件.get_pin('d:2:o') #D2腳位
 PWM輸出端點 = Arduino控制板物件.get_pin('d:3:p') #D3腳位
 Servo控制端點 = Arduino控制板物件.get_pin('d:4:s') #D4腳位
a0 = uno.get_pin('a:0:i') #a0為類比輸入
d3 = uno.get_pin('d:3:p') #d3為PWM輸出
使用pyFirmata設計控制程式 3/6
 讀取IO資料
 IO端點物件.read()
p = a0.read() #讀取a0端點資料,傳回值0.0~1.0
 輸出IO資料
 IO端點物件.write(value)
d3.write(p) #輸出資料到d3端點
使用pyFirmata設計控制程式 4/6
 Python程式
from pyfirmata import Arduino, util
from time import sleep
uno = Arduino('COM3') #建立Arduino控制板物件
sleep(5)
it = util.Iterator(uno) #啟用Iterator防止讀取序列埠溢位
it.start()
a0 = uno.get_pin('a:0:i') #建立IO端點物件
d3 = uno.get_pin('d:3:p') #建立IO端點物件
try:
while True:
p = a0.read() #讀取a0端點資料,傳回值0.0~1.0
print(p) #顯示a0類比輸入值
d3.write(p) #在d3輸出對應的PWM值
except KeyboardInterrupt:
uno.exit()
使用pyFirmata設計控制程式 5/6
使用pyFirmata設計控制程式 6/6
Arduino A0讀值
 使用Firmata方式,Arduino控制板被當成主機的IO擴充板,資料處
理及控制邏輯全部由主機端Python程式處理,並沒有充份使用
Arduino控制板
 pySerial是⼀個序列埠傳輸模組,讓主機端Python程式具備序列功
能,因此Arduino控制板視為⼀個序列裝置,Arduino控制板可獨立
進行前端資料處理及控制,必要時Arduino控制板與主機端才透過序
列傳輸互動
pySerial簡介
Python應用程式
pySerial
Arduino prog
Serial Communication
 測試電路
 收到主機"LED_ON"命令,開啟LED
 收到主機"LED_OFF"命令,關閉LED
 火焰偵測器觸發時,每5秒傳送" FIRE_ALARM"訊息到主機
使用pySerial設計控制程式 1/12
火焰偵測器
 Arduino控制程式
#define LED 3
#define FIRE_SENSOR 2
String cmd;
void setup() {
pinMode(LED, OUTPUT);
pinMode(FIRE_SENSOR, INPUT);
Serial.begin(9600);
}
void loop() {
if (digitalRead(FIRE_SENSOR) == HIGH) {
Serial.println("FIRE_ALARM"); //每5秒傳送火警訊號
delay(5000);
}
使用pySerial設計控制程式 2/12
14
if (Serial.available()) { //檢查序列埠
cmd = Serial.readStringUntil('n'); //讀取傳入的字串直到'n'字元
if (cmd == "LED_ON") { //收到"LED_ON"命令
digitalWrite(LED, HIGH); //開燈
Serial.println("已開啟LED"); //回應訊息給主機端
} else if (cmd == "LED_OFF") { //收到"LED_OFF"命令
digitalWrite(LED, LOW);
Serial.println("已關閉LED");
}
}
}
使用pySerial設計控制程式 3/12
15
 安裝pySerial模組
 pip install pyserial
使用pySerial設計控制程式 4/12
 安裝keyboard模組
 pip install keyboard
使用pySerial設計控制程式 5/12
 建立序列通訊物件
 serial.Serial(通訊埠, 傳輸速率);
import serial
COM_PORT = 'COM3'
BAUD_RATES = 9600
com = serial.Serial(COM_PORT, BAUD_RATES);
使用pySerial設計控制程式 6/12
18
 傳送資料
 序列通訊物件.write(data)
 data資料型別為bytes
 python字串為Unicode編碼,必須使用encode()將傳輸資料轉換為
byte編碼,或直接以b指定為byte型別
com.Write('LED_ONn'.encode()); #傳送控制命令
com.Write(b'LED_OFFn');
使用pySerial設計控制程式 7/12
19
 接收資料
 序列通訊物件.read()
 讀取1個字元資料
 序列通訊物件.read(n)
 最多讀取n個字元資料
 序列通訊物件.readline()
 讀取⼀行字串資料(以'n'結束)
 必須使用decode()將接收的字串資料轉換為unicode編碼
mcu_feedback = com.readline().decode() #接收回應訊息並解碼
print('控制板回應:', mcu_feedback)
使用pySerial設計控制程式 8/12
 檢查按鍵動作
 keyboard.is_pressed('ESC')
import keyboard
if keyboard.is_pressed('1'):
print('傳送開燈指令')
com.write(b'LED_ONn') #傳送命令字串
sleep(0.5)
使用pySerial設計控制程式 9/12
 Python程式
import serial
from time import sleep
import keyboard
COM_PORT = 'COM3'
BAUD_RATES = 9600
com = serial.Serial(COM_PORT, BAUD_RATES)
try:
print('按0開燈、按1關燈、按ESC關閉程式')
while True:
if keyboard.is_pressed('ESC'):
print('再見!')
com.close() #關閉序列埠
break #中止程式迴圏
使用pySerial設計控制程式 10/12
if keyboard.is_pressed('1'):
print('傳送開燈指令')
com.write(b'LED_ONn') #傳送命令字串
sleep(0.5) #暫停0.5秒,再執行底下接收回應訊息的迴圈
if keyboard.is_pressed('0'):
print('傳送關燈指令')
com.write(b'LED_OFFn')
sleep(0.5)
while com.in_waiting: #檢查序列埠
mcu_feedback = com.readline().decode() #接收回應訊息並解碼
print('控制板回應:', mcu_feedback)
except KeyboardInterrupt:
com.close()
print('再見!')
使用pySerial設計控制程式 11/12
使用pySerial設計控制程式 12/12

Python與Ardinio整合應用