天天看點

用樹莓派玩轉藍牙

作者:Vamei 出處:http://www.cnblogs.com/vamei 嚴禁轉載。

藍牙是一個使用廣泛的無線通信協定,這兩年又随着物聯網概念進一步推廣。我将介紹藍牙協定,特别是低功耗藍牙,并用樹莓派來實踐。樹莓派3中内置了藍牙子產品。樹莓派通過UART接口和該子產品通信。樹莓派1和樹莓派2中沒有内置的藍牙子產品,不過你可以通過USB安裝額外的藍牙擴充卡。

藍牙最初由愛立信創制,旨在實作可不同裝置之間的無線連接配接。藍牙無線通信的頻率在2.4GHz附近,和WiFi一樣,都屬于特高頻。相對于低頻信号來說,高頻傳輸的速度比較快,穿透能力強,但傳輸距離比較受限。在沒有遮蔽和幹擾的情況下,藍牙裝置的最大通信距離能達到30米。但在大多數情況下,藍牙的實際通信距離在2到5米。相比之下,低頻433MHz裝置的通信距離很容易超過百米。是以,藍牙常用于近距離的無線裝置,比如無線滑鼠和鍵盤。

用樹莓派玩轉藍牙

藍牙的标志 

藍牙的基本工作流程如下:

廣播/掃描:通信的一方向外廣播自己的資訊。另一方通過掃描知道自己周邊有哪些藍牙裝置在廣播,這些裝置的位址是什麼,以及是否可以連接配接。

連接配接:通信的一方向另一方發起連接配接請求。雙方通過一系列的資料交換建立連接配接。

資料通信

根據細節上的差别,藍牙通信又細分為兩種:經典藍牙和低功耗藍牙。早期的藍牙通信方式稱為經典藍牙(classic bluetooth)。經典藍牙中的資料傳輸協定是串行仿真協定RFCOMM。RFCOMM仿真了常見的序列槽連接配接。資料從一端輸入,從另一端取出。經典藍牙的開發非常簡單。基于序列槽開發的有線鍵鼠程式,就可以直接用于RFCOMM連接配接的無線鍵鼠。此外,經典藍牙可以快速傳輸資料。是以,諾基亞N95這樣的早期智能手機,也用RFCOMM來互傳圖檔和檔案。

用樹莓派玩轉藍牙

RFCOMM通信

經典藍牙的缺點是比較耗電。後來,諾基亞發明了一種可以降低功耗的藍牙通信方式。2010年出台的藍牙4.0把這種通信方式規範為“低功耗藍牙”(BLE,Bluetooth Low Energy)。BLE把通信雙方分為非對稱的雙方,盡量讓其中的一方承擔主要的開銷,減少另一方的負擔。舉例來說,手環電量少,而且需要長時間待機。BLE通信的主要負擔可以放在電量較充裕且充電友善的手機一側,進而減少手環的能耗。

用樹莓派玩轉藍牙

手環作為外設

BLE通信一般也包含廣播/掃描的步驟。主動發起廣播的裝置稱為外設(Peripheral),掃描裝置稱為中心裝置(Central)。BLE連接配接成功之後,就可以開始資料傳輸。BLE的資料傳輸協定是ATT和GATT協定。ATT是GATT的基礎。ATT協定把通信雙方分為伺服器(server)和客戶(client)。客戶主動向伺服器發起讀寫操作。需要注意的是,ATT中的伺服器和客戶,與廣播階段的外設和中心裝置互相獨立。當然,在手環這樣的應用場景下,外設通常也是伺服器。ATT協定以屬性(attribute)為機關進行該資料傳輸。一個屬性的格式如下:

用樹莓派玩轉藍牙

ATT屬性

我們分别來了解屬性的不同部分:

handle:屬性的唯一編号,長度為16位。

type:屬性的類型。每種類型用一個UUID編号。

value:屬性的值。

permission:屬性的權限,分為無、可讀、可寫、可讀寫。

伺服器儲存了多個屬性。當客戶向伺服器請求時,伺服器會把自己的屬性清單發給客戶。随後,客戶可以向伺服器讀取或寫入某一個屬性值。用讀寫的方式,通信雙方實作了雙向通信。

用樹莓派玩轉藍牙

以智能手表為例。智能手表和手機配對後,手機可以用讀的方式獲得智能手表中某個屬性下儲存的步數,也可以用寫的方式寫入另一個屬性負責的時間。在讀寫操作中,都是由客戶采取主動,伺服器隻能被動應答。ATT還提供了通知(notification)的工作方式。當伺服器改變了某個屬性值時,可以主動通知訂閱了該屬性值的客戶。智能手表中的手勢識别,就可以通過通知的方式告知手機。這樣的話,手機就可以實時地獲知手勢改變資訊。

用樹莓派玩轉藍牙

GATT協定建構在ATT協定之上,為屬性提供了組織形式。GATT的最小組織單元是Characteristic,可以由數條屬性組成。下圖中就是一個Characteristic,用于傳輸紅外測溫獲得的資料。這個例子來自TI的SensorTag:

用樹莓派玩轉藍牙

 從左到右:handle(16進制),handle(10進制),type(16進制),type(文字說明),value(16進制),permission,備注

Characteristc的第一條屬性用于聲明屬性,其類型總是0x2803。這條聲明的value部分又可以細分為三部分。第一個部分是0x12,稱為Characteristic Properties,是GATT協定層面上的權限控制。其具體含義可參考資料。第二部分0x0025,是Characteristic值的handle。找到handle為0x0025的屬性,就在聲明屬性的下面一行。0x0025的value部分就是紅外溫度的真正數值。剩下的部分是該Characteristic的UUID,總共128位:

F000-AA01-0451-4000-B000-000000000000

檢查Characteristic值的那一行屬性,也就是0x0025屬性。它的類型也是該Characteristic UUID。除了128位的UUID,藍牙官方還提供了16位的UUID可供使用,可參考資料。

可以看到,一個Characterstic至少需要兩個屬性,一個用于聲明,一個用于儲存它的資料。除此之外,Characteristic還有稱為Descriptor的額外描述資訊。每個Decriptor占據一行。比如0x0027這個Descriptor,其屬性值是54:65:6D:70:7E:20:44:61:74:61,翻譯成ASCII就是:

Temp~ Data

此外,溫度機關、測量頻率等描述資訊也經常會以Descriptor的形式放入到Characteristic中。在下一個Characteristic聲明出現前的屬性,都是該Characteristic的Descriptor。

我們再來看更進階的組織機關Service。一個Service也有行屬性作為聲明,其類型UUID是0x2800。聲明屬性的值就是該Service的128位UUID。藍牙官方也提供了16位的UUID,預留給特定的Service,可參考資料。在下一個Service聲明出現前的屬性,都屬于該Service,比如下圖中從0x0023到0x002D的屬性:

用樹莓派玩轉藍牙

圖中包含了一個與紅外溫度計相關的Service。Service裡又有三個Characteristic,分别0x0024-0x0027、0x0028-0x002A、0x002B-0x002D。我已經介紹過第一個Characteristic。第二個Characteristic用于傳輸溫度計參數,第三個用于設定測溫頻率。

Service和Characteristic都是屬性的組織形式。客戶可以向伺服器請求Service和Characteristic清單,然後對其進行操作。GATT還提供了Profile,可以包括多個Service。不過,Profile并不像前面兩者那樣存在于伺服器。Profile是一種标準,用于說明一個特型裝置應該有哪些Service。比如說,HID(Human Interface Device)這種Profile,就說明了藍牙輸入裝置應該提供的Service。藍牙官方定義的Profile可參考資料。

我們用樹莓派來深入實踐上面學到的藍牙知識。首先要在樹莓派上安裝必要的工具。BlueZ是Linux官方的藍牙協定棧。你可以通過BlueZ提供的接口,進行豐富的藍牙操作。Raspbian中已經安裝了BlueZ。我使用的版本是5.43。你可以檢查自己的BlueZ版本:

低版本的BlueZ對低功耗藍牙的支援有限。如果你的使用版本低于5.43,那麼我建議你更新BlueZ。

你可以用下面的指令檢查BlueZ的運作狀态:

我的傳回結果是:

可以看到,藍牙服務已經打開,并在正常運作。

你可以用下面指令手動啟動或關閉藍牙服務:

此外,你還可以讓藍牙服務随系統啟動:

在Raspbian中,基本的藍牙操作可以通過bluez中的bluetoothctl指令進行。該指令運作後,将進入到一個新的Shell。在這個shell中輸入:

将顯示樹莓派上可用的藍牙子產品,例如:

運作scan指令,開啟掃描:

掃描啟動後,用devices指令,可以列印掃描到藍牙裝置的MAC位址和名稱,例如:

此外,你還可以用help指令獲得幫助。使用結束後,你可以用exit指令推出bluetoothctl。

除了bluetoothctl,在Raspbian是shell中可以通過hciconfig來控制藍牙子產品。比如開關藍牙子產品:

指令中的hci0指的是0号HCI裝置,即樹莓派的藍牙擴充卡。 

與此同時,你可以用下面指令來檢視藍牙裝置的工作日志: 

bluez本身還提供了連接配接和讀寫工具。但不同版本的bluez相關功能的差異比較大,而且使用起來不太友善,是以我下面使用Node.js的工具來實作相關功能。

下一步,我們嘗試用樹莓派進行BLE通信。我們先把一個樹莓派改造成BLE外設,同時它也将充當連接配接建立後的伺服器。這個過程較為複雜。你可以借用Node.js下的bleno庫。首先,安裝Node.js: 

第一行的指令是為了確定安裝高版本的Node.js。

安裝bleno: 

運作pizza的例子: 

你可以在node_modules/bleno/examples/pizza/看到源代碼,或者到github檢視。這個例子提供了一個Service,它的UUID是1333-3333-3333-3333-3333-333333333337。Service中包含了三個Characteristics,分别是用于披薩餅參數、配料參數和烤披薩:

功能

權限

UUID

披薩餅選項

讀/寫

13333333333333333333333333330001

配料

13333333333333333333333333330002

烤披薩

寫/通知

13333333333333333333333333330003

通過這些Characteristic,我們可以對樹莓派進行BLE讀寫。讀寫操作會作用于一個代表比薩的對象。披薩餅選項有:

數值

描述

0x00

正常

0x01

0x02

配料是一個8位的參數,每一位代表了一種配料。當這一位是1時,那麼說明添加該配料:

第n位

7

6

5

4

3

2

1

SAUSAGE

BELL_PEPPERS

PINEAPPLE

CANADIAN_BACON

BLACK_OLIVES

EXTRA_CHEESE

MUSHROOMS

PEPPERONI

是以,0x1A代表了添加MUSHROOMS、BLACK_OLIVES、CANADIAN_BACON,感覺味道還不錯。

對于烤披薩來說,寫操作設定了烘烤的溫度和時間。時間到了之後,中心裝置會發出通知,告訴用戶端烘烤完成。我們下一步将用另一個樹莓派作為BLE中心裝置。不過,即使你沒有額外的樹莓派,你可以用iPhone上LightBlue這樣的App來測試這一部分完成的BLE外設。

我們拿另一個作為BLE的中心裝置進行掃描,并發起連接配接請求。連接配接建立後,該伺服器将充當客戶。和bleno對應,Node.js下有一個叫noble的項目,可以便捷地完成這一任務。首先,安裝noble:

noble中有一個同樣名為pizza的例子,不過這個例子實作的是用戶端。運作該例子:

這個例子将自動執行掃描、連接配接、服務發現、資料傳輸的全過程。如果你把bleno和noble部署到兩個樹莓派上,就可以在這兩個樹莓派之間進行藍牙通信了。如果你想自定義開發,那麼可以在node_modules/noble/examples/pizza/參考源代碼,或者到github檢視。

蘋果在BLE的基礎上推出了iBeacon協定。iBeacon使用了BLE的廣播部分,但不建立連接配接。一個遵守iBeacon協定的外設稱為Beacon。Beacon會廣播自己的身份資訊和發射信号的強度。中心裝置接收到廣播之後,除了可以獲知Beacon的身份之外,還能通過信号的衰減算出自己與Beacon的距離。在一個典型的超市應用場景中,每件商品可以帶上一個Beacon。消費者可以用手機看到自己周圍有哪些商品,從業人員也可以用手機來清點貨物。商家還可以在伺服器上提供商品相關的質保、促銷等資訊。使用者可以根據Beacon的編号,獲得這些附加資訊。

用樹莓派玩轉藍牙

我們把配備了藍牙子產品的樹莓派改造成一個Beacon。既然Beacon隻使用了藍牙中的廣播,那麼應該關閉樹莓派的掃描,打開廣播,并且不接受藍牙連接配接:

下一步,把廣播資訊改為符合iBeacon協定的内容:

上面的指令附加了一串16進制資訊。其中0x08說明了整條資訊是藍牙指令,0x0008說明後面的内容将作為廣播資訊。

1E是廣播資訊開始的标志。按照藍牙通信的規定,廣播資訊最多有31個位元組。1E後面的廣播資訊分為兩組:

每一組一開始的一個位元組說明了該組資訊的長度。02說明了2個位元組,1A說明是26個位元組。随後一個位元組說明了改組資訊的類型。第一組的01說明了該組資訊是藍牙控制标志,第二組的FF說明了該組是藍牙制造商相關資訊。

我們來看第二組資訊的細節:

4C 00是制造商資訊,即蘋果。

02 15是iBeacon協定辨別。

63 6F 3F 8F 64 91 4B EE 95 F7 D8 CC 64 A8 63 B5部分是裝置的UUID,通常是使用者編号。

UUID後面的00 01是主編号(Major)。

再往後的00 02是次編号(Minor)。通過UUID、主編号、次編号的組合,我們可以唯一地确定iBeacon裝置。

最後的C5說明了藍牙信号強度,即在1米處測得的該Beacon的RSSI值。中心裝置把接收到的信号強度和該信号強度對比,就可以知道信号衰減了多少,進而推算出自己與Beacon的距離。由于我這裡寫入的C5沒有經過校準,是以距離測量很可能不準确。

在iPhone上安裝應用Locate Beacon來測試。當我進入到樹莓派的廣播範圍時,該應用就會顯示出手機距離樹莓派的距離。

用樹莓派玩轉藍牙

使用結束後,可以用下面指令來恢複掃描和停止廣播:

這裡簡單介紹了藍牙協定,特别是低功耗藍牙。我以樹莓派的藍牙子產品為基礎,實作了BLE通信。

歡迎閱讀“騎着企鵝采樹莓”系列文章 

我的部落格即将搬運同步至騰訊雲+社群,邀請大家一同入駐:https://cloud.tencent.com/developer/support-plan

如果你喜歡這篇文章,歡迎推薦。

繼續閱讀