Python 及 Firmata
Tags: Arduino, IoT

在上一章節中我們使用了PySerial函示庫來進行簡單的操作，但是他缺乏了Firmata的通訊能力，而PyFirmata他也是Python的一個函示庫，看他的名稱就知道他是支援Firmata的，Python也有提供其他支援Firmata的函示庫，但我們這邊聚焦在PyFirmata上。

安裝PyFirmata與測試

安裝PyFirmata的方法跟安裝PySerial一樣，但是由於PyFirmata有最新版本了，我們這邊直接安裝PyFirmata2而非是PyFirmata

輸入下面指令

pip install pyFirmata2

2. 要使用Firmata協定時，我們需要再次的上傳StandarFirmata草稿碼到Arduino板子上

3. 開啟Python，並輸入下面的指令

from pyfirmata2 import Arduino

在這邊我們將pyfirmata2中的Arduino套件給引用近來。

4. 接下來我們要去設定腳位，跟之前PySerial類似的設定方法，在這邊我們會先去設定我們的阜號，接下來再去設定我們設號的port跟Arduino連接起來

port ='COM8'

board = Arduino(port)

而由於我們使用的版本是pyfirmata2，而非pyfirmata在這次更新成2之後，提供了自動辨識port腳位，所以我們在port的位置可以更換成以下的命令

board = Arduino(Arduino.AUTODETECT)

而在我們設定完成之後，python與開發板間的通訊便已經連接好了，Arduino上會有兩個Led燈開始閃爍。在之前的測試中，我們使用現成的Firmata軟體來控制pin13Led燈的閃爍，而現在我們嘗試使用Python來做控制。

5. 我們讓Pin13亮起來

pin = 13

board.digital[pin].write(1)

6. 接下來我們讓燈關掉

board.digital[pin].write(0)

7. 當然我們也可以讀取腳位的狀態

board.digital[pin].read()

而當我們把這些指令編輯成一個py文件，再去執行的話，我們也就不需要再去動用到Arduino草稿碼了。

開發版設定

在PyFirmata2這次的更新之後，可支援的開發版有UNO、MEGA、DUE、NANO這四塊板子，且在於切換開發版的時，不需要重構程式碼即可使用。

但當我們都不是使用以上這些開發版的時候，我們可以參考UNO開發版的範例來進行修改成目前所使用的開發板來實作

arduino = {

'digital': tuple(x for x in range(14)),

'analog': tuple(x for x in range(6)),

'pwm': (3, 5, 6, 9, 10, 11),

'use_ports': True,

'disabled': (0, 1) # Rx, Tx, Crystal

}

根據上面UNO的示範，我們可以去依照我們開發版的腳位去做相關的設定，所以我們需要客製化Dictionary物件，去像digital、analog、pwm、use_ports、disabled等腳位去做相關的更動。而在我們設定好我們的開發板參數之後，要用以下指令來呼叫開發板，在乎教之後我們便將開發板給同步了

board.set_layout(開發板名稱)

使用PyFirmata方法

在這一小節我們將重頭講起如何使用PyFirmata，而作為操作Arduino開發板與Firmata通訊協定的一部分，我們需要將Arduino開發板作為一個變數(參數)，PyFirmata能讓使用者將開發粄作為一個變數去使用，而在使用前我們需要去將套件給引入，並將她的COM給設定好

from pyfirmata2 import Arduino

board = Arduino(Arduino.AUTODETECT)

訊號調用

在我們指派完變數board後，我們便可以開始做一些處理，例如讀取某個腳位或使用此變數傳遞訊號到腳位。而在我們要去指定某一個腳位的角色時，我們會用get_pin()方法。在下列程式碼中，d代表數位腳位，7為腳位編號，i則代表腳位類型為輸入。若此時我們要的訊號是邏輯訊號，則d的位置要改成a。若是要輸出訊號則要將i的位置改成o，若訊號是PWM訊號，i的位置需要改成p

digital_0 = board.get_pin('d:3:i')

analog_0 = board.get_pin('a:0:o')

pin3 = board.get_pin('d:3:p')

而此時我們便可以對被指定角色的腳位去做一些動作，像是讀取或是輸入:

Value = digital_0.read()

pin3.write(0.6)

當然你不想指定腳位的角色也是可以去命令他去輸入跟讀取的:

pin1 = 13

board.digital[pin1].write(1)

board.digital[pin1].read()

Arduino的類比腳位以線性比例將0–5V間的輸入電壓轉換成0–1023，然而

邏輯訊號調用

上面的那兩個函式是在處理數位訊號會用到的，接下來說明邏輯訊號。而邏輯訊號使用上較數位訊號更佳的複雜，首先我們需要先去設定我們採樣的頻率，簡單來說就是指一秒鐘我們要收集多少數據，接下來我們有兩種去讀取數值的方式，第一種是用read的方式，這種方式比較單純，直接寫read()就可以了，第二種方法是用調用的，也就是常跟class或是def一起使用，而他們在使用後都需要加上enable_reporting，這樣資料才會回傳回來

board.samplingOn(1000 / 100)

board.analog[1].read()

board.analog[0].register_callback(myCallback)

board.analog[0].enable_reporting()

以下來做個示範吧，下面的範例是使用調用的方式去做取值

def callBack(data):

print(data)

board.samplingOn(1000 / 100)

board.analog[0].register_callback(callBack)

board.analog[0].enable_reporting()

PWM與SERVO

在處理PWM與SERVO訊號前，我們先講一個函式可以幫助我們輕鬆的去設定目前pin腳使用哪一種方法，有輸出、輸入、伺服馬達、PWM訊號可以選擇，但是在使用PWM跟SERVO前我們需要先把他們import進來

from pyfirmata import Arduino, PWM , SERVO board.digital[1].mode = Output

board.analog[1].mode = Input

board.digital[2].mode = PWM

board.digital[3].mode = SERVO

PWM補充

首先補充一下PWM訊號，在電子學領域中，PWM是一種訊號調變技術，大量用於提供零件電力控制，與數位腳位配合後，PWM便以方波及控制訊號寬度取得類比訊號。Arduino開發板的數位信號只有兩種狀態5V跟0V，但是可以藉由控制HIGH與LOW之間的開關規則來產生方波脈衝。藉由改變這些脈衝的寬度，可以產生任何介於0V-5V的電壓值，從下圖來看的話，有一個方波為25%的工作週期寬度，也就意味著我們有0.25∗5V=1.25V0.25∗5V=1.25V的電壓

Arduino語言使用analogWrite()功能之援PWM，能版0到5V的電壓值線性對應到0到255，以50%工作週期(2.5V)來說轉換過去的值為127，同樣的20%為64

PWM

在Arduino中，PWM為0到255之間的訊號，代表工作週期0到100%的脈衝寬度，pyfirmata函示庫中簡化了PWM的使用方法，我們只需要將數值變成 0-1.0 之間的浮點數就可以了，如果想要一個50%的工作週期，只需要輸入0.5就可以了，在輸入後pyfirmata會自動轉換傳送適當的數值到Arduino開發板:

board.digital[pin].mode = PWM

board.digital[pin].write(0.5)

或是使用，以下方法

pwmPin = board.getPin('d:13:p')

pwmPin.write(0.5)

SERVO

在伺服馬達的部分，我們一開始依樣需要先去將腳位指定模式成SERVO，接下來才能去做相關的設定

board.digital[pin].mode = SERVO

接下來我們要去設定角度，設定腳度也很簡單，直接寫入0–180內的數值就好

board.digital[pin].write(90)

其他函式

除了上面介紹到的函式還有一些函式也是可能用到的

1.可以使用在設定伺服馬達的初始角度

servo_config(pin,min_pluse=544,max_pluse = 2400,angle=0)

# 最小脈衝值、最大脈衝、起始角度

2. 跟time模組提供的sleep()很像，但他是以秒來提供無間段的暫停

pass_time(seconds)

3. 查看開發版的Firmata版本

board.get_firmata_version()

4. 程式執行後切斷Firmata與Arduino的連接

board.exit()

範例

讀邏輯訊號

#!/usr/bin/python3 from pyfirmata2 import Arduino

import time PORT = Arduino.AUTODETECT

# PORT = '/dev/ttyACM0' # prints data on the screen at the sampling rate of 50Hz

# 印出採樣頻率50的數據 # It uses a callback operation so that timing is precise and the main program can just go to sleep. class AnalogPrinter: def __init__(self):

# sampling rate: 50Hz

self.samplingRate = 100

self.timestamp = 0

self.board = Arduino(PORT) def start(self):

self.board.analog[0].register_callback(self.myPrintCallback)

self.board.samplingOn(1000 / self.samplingRate)

self.board.analog[0].enable_reporting() def myPrintCallback(self, data):

print("%f,%f" % (self.timestamp, data))

self.timestamp += (1 / self.samplingRate) def stop(self):

self.board.samplingOff()

self.board.exit() print("Let's print data from Arduino's analogue pins for 10secs.") # Let's create an instance

analogPrinter = AnalogPrinter() # and start DAQ

analogPrinter.start() # let's acquire data for 10secs. We could do something else but we just sleep!

time.sleep(10) # let's stop it

analogPrinter.stop() print("finished")

總結

在這一小節中，我們從Firmata的安裝講到他的使用方法，最後用一個小範例做一個結束，而這個範例是Firmata2在Github上的範例，他還有提供其他的範例，可以自己去查看