用树莓派玩转蓝牙

树莓派 徐 自远 768℃

作者:Vamei 出处:http://www.cnblogs.com/vamei 严禁转载。

 

蓝牙是一个使用广泛的无线通信协议,这两年又随着物联网概念进一步推广。我将介绍蓝牙协议,特别是低功耗蓝牙,并用树莓派来实践。树莓派3中内置了蓝牙模块。树莓派通过UART接口和该模块通信。树莓派1和树莓派2中没有内置的蓝牙模块,不过你可以通过USB安装额外的蓝牙适配器。

 

蓝牙介绍

蓝牙最初由爱立信创制,旨在实现可不同设备之间的无线连接。蓝牙无线通信的频率在2.4GHz附近,和WiFi一样,都属于特高频。相对于低频信号来说,高频传输的速度比较快,穿透能力强,但传输距离比较受限。在没有遮蔽和干扰的情况下,蓝牙设备的最大通信距离能达到30米。但在大多数情况下,蓝牙的实际通信距离在2到5米。相比之下,低频433MHz设备的通信距离很容易超过百米。因此,蓝牙常用于近距离的无线设备,比如无线鼠标和键盘。

蓝牙的标志

 

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

  1. 广播/扫描:通信的一方向外广播自己的信息。另一方通过扫描知道自己周边有哪些蓝牙设备在广播,这些设备的地址是什么,以及是否可以连接。
  2. 连接:通信的一方向另一方发起连接请求。双方通过一系列的数据交换建立连接。
  3. 数据通信

根据细节上的差别,蓝牙通信又细分为两种:经典蓝牙和低功耗蓝牙。早期的蓝牙通信方式称为经典蓝牙(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属性

我们分别来理解属性的不同部分:

  1. handle:属性的唯一编号,长度为16位。
  2. type:属性的类型。每种类型用一个UUID编号。
  3. value:属性的值。
  4. 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

我们用树莓派来深入实践上面学到的蓝牙知识。首先要在树莓派上安装必要的工具。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通信。我们先把一个树莓派改造成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 0
描述 SAUSAGE BELL_PEPPERS PINEAPPLE CANADIAN_BACON BLACK_OLIVES EXTRA_CHEESE MUSHROOMS PEPPERONI

 

因此,0x1A代表了添加MUSHROOMS、BLACK_OLIVES、CANADIAN_BACON,感觉味道还不错。

 

对于烤披萨来说,写操作设定了烘烤的温度和时间。时间到了之后,中心设备会发出通知,告诉客户端烘烤完成。我们下一步将用另一个树莓派作为BLE中心设备。不过,即使你没有额外的树莓派,你可以用iPhone上LightBlue这样的App来测试这一部分完成的BLE外设。

 

树莓派作为BLE中心设备

我们拿另一个作为BLE的中心设备进行扫描,并发起连接请求。连接建立后,该服务器将充当客户。和bleno对应,Node.js下有一个叫noble的项目,可以便捷地完成这一任务。首先,安装noble:

 

noble中有一个同样名为pizza的例子,不过这个例子实现的是客户端。运行该例子:

这个例子将自动执行扫描、连接、服务发现、数据传输的全过程。如果你把bleno和noble部署到两个树莓派上,就可以在这两个树莓派之间进行蓝牙通信了。如果你想自定义开发,那么可以在node_modules/noble/examples/pizza/参考源代码,或者到github查看。

 

树莓派作为Beacon

苹果在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通信。

转载请注明:徐自远的乱七八糟小站 » 用树莓派玩转蓝牙

喜欢 (0)

苏ICP备18041234号-1 bei_an 苏公网安备 32021402001397号