调试硬件NRF51822 树莓派3
软件pyblueZ或者bluepy
蓝牙地址或设备地址是蓝牙芯片制造的全球唯一的48位地址。
传输协议:
RFCOM+TCP
RFCOM和TCP一样,提供大致相同的服务和可靠性保证。它是模仿RS-232设计的,方便制造商将蓝牙功能添加到下游的串口设备中。RFCOMM是射频通信协议,它可以仿真串行电缆接口协议,符合ETSI0710串口仿真协议。通过RFCOMM,蓝牙可以在无线环境下实现对高层协议,如PPP、TCP/IP、WAP等的支持。另外,RFCOMM可以支持AT命令集,从而可以实现移动电话机和传真机及调制解调器之间的无线连接。
RFCOM和TCP的不同支出在于TCP在机器上支持65535个开放端口,而RFCOM只允许30个 (最可靠的协议)
L2CAP+UDP (最优的协议)
L2CAP提供了一个面向连接的协议。
L2CAP信道有三种类型:
A、面向连接信道:Connection-OrientedCO,用于两个设备之间的数据通信。
B、无连接信道:Connection-LessCL,用来向一组设备广播方式传输数据。CID为固定值:0x0002。
C、信令信道:Signaling,用于创建CO通道,可以通过协商改变CO信道的特性。
当设备地址和传输协议确定后,就该确定端口了。
L2CAP 的端口称为PSM RFCOM的端口称为通道。
protocol |
terminology |
reserved/well-known ports |
dynamically assigned ports |
TCP |
port |
1-1024 |
1025-65535 |
UDP |
port |
1-1024 |
1025-65535 |
RFCOMM |
channel |
none |
1-30 |
L2CAP |
PSM |
odd numbered 1-4095 |
odd numbered 4097 - 32765 |
建立连接,传输数据
通过命令bluetoothctl -v查看可知,树莓派3上的blueZ是5.23的版本,有点老,后面的bluetoothctl命令很多都没有,所以我进行重新安装,将它升级成了5.43的版本。
sudo apt-get update
sudo apt-get upgrade
sudo apt-get dist-upgrade
sudo apt-get install -y libusb-dev libdbus-1-dev libglib2.0-dev libudev-dev libical-dev libreadline-dev
sudo wget http://www.kernel.org/pub/linux/bluetooth/bluez-5.43.tar.xz
sudo tar xf bluez-5.43.tar.xz
cd bluez-5.43/
sudo ./configure
sudo make
sudo make install
sudo reboot
# check version
bluetoothctl -v
sudo vim /lib/systemd/system/bluetooth.service
# Add --experimental to this lane
ExecStart=/usr/local/libexec/bluetooth/bluetoothd --experimental
sudo systemctl daemon-reload
sudo systemctl restart bluetooth
sudo hciconfig hci0 up
sudo reboot
sudo usermod -G bluetooth -a pi
sudo reboot
sudo apt-get install python-dev
sudo apt-get install libbluetooth-dev
sudo pip install pybluez (如果是python3的话执行sudo pip3 install pybluez)
关于通过树莓派3和经典蓝牙的连接,这里是用HC-05和ET10 (双模)来测试的,他们都是是支持经典模式协议SPP协议的
在通过bluetoothctl工具进行连接的时候出现错误
Failed to connect: org.bluez.Error.NotAvailable
经过pair后,可以连接,但是瞬间就断开,还是相同的错误,经过查找,找到以下解决方法:
连接命令:sudo rfcomm connect hci0 00:1B:10:F1:FB:D4
http://blog.csdn.net/qq_33518042/article/details/53503492
例程(这里例程好似客服端的,将透传模块看做是服务器端):
#!/usr/bin/env python
import bluetooth
import subprocess
service_matches = bluetooth.find_service( address = "00:1B:10:F1:FB:D4" )
if len(service_matches) == 0:
print "couldn't find the FooBar service"
sys.exit(0)
first_match = service_matches[0]
port = first_match["port"]
name = first_match["name"]
host = first_match["host"]
print "connecting to \"%s\" on %s port:%s" % (name, host, port)
sock=bluetooth.BluetoothSocket( bluetooth.RFCOMM )
sock.connect((host, port))
while True:
sock.send("012345678901234567890123456789!!\r\n")
sock.close()
参考:http://people.csail.mit.edu/albert/bluez-intro/x290.html
http://htmlpreview.github.io/?https://github.com/karulis/pybluez/blob/master/docs/index.html
开始调试蓝牙。首先简单的例程:
#!/usr/bin/env python
import bluetooth
print("performing inquiry...")
nearby_devices = bluetooth.discover_devices(
duration=8, lookup_names=True, flush_cache=True, lookup_class=False)
print("found %d devices" % len(nearby_devices))
for addr, name in nearby_devices:
try:
print(" %s - %s" % (addr, name))
except UnicodeEncodeError:
print(" %s - %s" % (addr, name.encode('utf-8', 'replace')))
出现了错误:
File "/usr/local/lib/python2.7/dist-packages/bluetooth/bluez.py", line 26, in discover_devices
device_id = _bt.hci_get_route()
OSError: [Errno 19] No such device
可能是因为我蓝牙没有打开吧,我把蓝牙打开后程序正常运行
注意:本例程不能发现ble(低功耗蓝牙4.0)设备
结果:
performing inquiry...
found 2 devices
A4:44:D1:AA:9B:6A - note 3
AC:CF:85:B0:AE:A4 - huawei
现在蓝牙开发的整体思路是通过脚本来运行蓝牙,然后通过pybulez来控制数据传输
blueZ开发参考:
http://htmlpreview.github.io/?https://github.com/karulis/pybluez/blob/master/docs/index.html
http://people.csail.mit.edu/albert/bluez-intro/index.html
通过RFCOM进行数据传输(服务器端):
例程:
#!/usr/bin/env python
import bluetooth
import subprocess
sub=subprocess.Popen("sudo hciconfig hci0 up",shell=True) //开启设备
sub=subprocess.Popen("sudo hciconfig hci0 piscan",shell=True) //使设备能够被扫描到
server_sock=bluetooth.BluetoothSocket( bluetooth.RFCOMM )
port = 1
server_sock.bind(("",port))
server_sock.listen(1)
client_sock,address = server_sock.accept()
print "Accepted connection from ",address
data = client_sock.recv(1024)
print "received [%s]" % data
注意:本例程不适用ble(低功耗蓝牙4.0)设备
Hciconfig 命令:http://xu1347.blog.163.com/blog/static/1613788612011624023429/
Hcitool 工具:http://blog.chinaunix.net/uid-27875-id-5187357.html
现在先介绍一下命令连接。命令连接有三种,bluetoothctl、gatttool、hcitool我测试通过的是两种bluetoothctl。不过可能是因为版本的问题,我的bluetoothctl的命令少了一些,智能进行简单的连接操作
pi@scream:~$ sudo bluetoothctl
[NEW] Controller B8:27:EB:35:34:90 scream [default]
[NEW] Device C4:62:EA:DB:72:F3 Galaxy Note3
[bluetooth]# power on
Changing power on succeeded
[bluetooth]# scan on
Discovery started
[CHG] Controller B8:27:EB:35:34:90 Discovering: yes
[NEW] Device 55:7E:64:96:79:F5 55-7E-64-96-79-F5
[NEW] Device E3:47:55:D3:22:77 SCREAM
[NEW] Device 56:11:F4:A1:AA:0F 56-11-F4-A1-AA-0F
[bluetooth]# agent on
Agent registered
[bluetooth]# connect E3:47:55:D3:22:77
Attempting to connect to E3:47:55:D3:22:77
[CHG] Device E3:47:55:D3:22:77 Connected: yes
Connection successful
[CHG] Device E3:47:55:D3:22:77 UUIDs:
00001800-0000-1000-8000-00805f9b34fb
00001801-0000-1000-8000-00805f9b34fb
6e400001-b5a3-f393-e0a9-e50e24dcca9e
[CHG] Device E3:47:55:D3:22:77 Appearance: 0x1234
[NEW] Device F8:DF:A8:1D:C8:02 F8-DF-A8-1D-C8-02
[bluetooth]# disconnect E3:47:55:D3:22:77
Attempting to disconnect from E3:47:55:D3:22:77
Successful disconnected
[CHG] Device E3:47:55:D3:22:77 Connected: no
中间少了个pair命令,不过我之前pair过所以没问题。
参考:http://blog.csdn.net/bona020/article/details/52141363
参考:https://www.jerryzone.cn/raspi-bluetooth-socket/
在开启的过程中可能会出现错误:Failed to connect: org.bluez.Error.Failed
这是由于蓝牙设备没有上电造成的,可通过如下命令解决此问题:
rfkill unblock bluetooth
hciconfig hci0 up
然后就是gatttool,之前这个命令来连接一直实现不了总是提示:
Error connect: Connection refused (111)
后来在网上找了解决的方法
首先:vim /etc/bluetooth/main.conf
在最下面添加 :
EnableLE = true
AttributeServer = true
DisablePlugins=pnat
使用的时候通过sudo gatttool -t random -b E3:47:55:D3:22:77 -I来打开
感觉主要应该是因为命令中加入了random所以才能连上的
如下
pi@scream:~$ sudo gatttool -t random -b E3:47:55:D3:22:77 -I
[E3:47:55:D3:22:77][LE]> connect
Attempting to connect to E3:47:55:D3:22:77a
Connection successful
[E3:47:55:D3:22:77][LE]> primary
attr handle: 0x0001, end grp handle: 0x0007 uuid: 00001800-0000-1000-8000-00805f9b34fb
attr handle: 0x0008, end grp handle: 0x000b uuid: 00001801-0000-1000-8000-00805f9b34fb
attr handle: 0x000c, end grp handle: 0xffff uuid: 6e400001-b5a3-f393-e0a9-e50e24dcca9e
[E3:47:55:D3:22:77][LE]> characteristics
handle: 0x0002, char properties: 0x0a, char value handle: 0x0003, uuid: 00002a00-0000-1000-8000-00805f9b34fb
handle: 0x0004, char properties: 0x02, char value handle: 0x0005, uuid: 00002a01-0000-1000-8000-00805f9b34fb
handle: 0x0006, char properties: 0x02, char value handle: 0x0007, uuid: 00002a04-0000-1000-8000-00805f9b34fb
handle: 0x0009, char properties: 0x20, char value handle: 0x000a, uuid: 00002a05-0000-1000-8000-00805f9b34fb
handle: 0x000d, char properties: 0x10, char value handle: 0x000e, uuid: 6e400003-b5a3-f393-e0a9-e50e24dcca9e
handle: 0x0010, char properties: 0x0c, char value handle: 0x0011, uuid: 6e400002-b5a3-f393-e0a9-e50e24dcca9e
[E3:47:55:D3:22:77][LE]> char-write-req 0x0011 24
Characteristic value was written successfully
但是第三种方法没有实现,在用hcitool进行连接的时候,总是出现错误
Could not create connection: Connection timed out
没有找到解决的办法。
源码下载地址:https://github.com/karulis/pybluez (0.22版本的)
可以通过 sudo git clone https://github.com/karulis/pybluez.git 来下载。
完成后来进行安装
sudo apt-get install python-dev
sudo apt-get install libbluetooth-dev
sudo pip install pybluez (如果是python3的话执行sudo pip3 install pybluez)
然后需要安装依赖:
pkg-config
libboost-python-dev
libboost-thread-dev
libbluetooth-dev >= 4.101 (前面已安装)
libglib2.0-dev (前面在安装blueZ5.43的时候应该也已安装)
python-dev(前面已安装)
分别运行命令:sudo apt-get install pkg-config
sudo apt-get install libboost-python-dev
sudo apt-get install libboost-thread-dev
sudo apt-get install libglib2.0-dev
然后进行下面的安装
sudo pip install pybluez[ble] (包含了gattlib)
sudo python setup.py install (在下载下来的pyblueZ的文件夹下运行)
sudo pip install -e .[ble]
通过对pyblue源码的查看,其ble功能用到的一些接口函数都是从gattlib模块中导入的。
关于gattlib模块可以参考pygattlib https://bitbucket.org/OscarAcena/pygattlib
例程:
#!/usr/bin/env python
from bluetooth.ble import GATTRequester
address="E3:47:55:D3:22:77"
nrf=GATTRequester(address, False)
nrf.connect( wait=True, channel_type="random")
nrf.write_by_handle(0x0011, "123456")
1、其中connect中的参数random很重要,之前一直没有添加这个参数,默认的是public,一直连接不上,后来添加了random,蓝牙可以和nrf51822连接了,是否需要加random需要看设备的地址类型, nRF51822采用的是Random Static address,在启动的时候协议栈从FICR里面读取作为设备的蓝牙地址.如果用户需要使用Public address,则需要使用sd_ble_gap_address_set()这个函数重新设定蓝牙地址。
2、write_by_handle()中的参数0x0011是char的handle。之前在用gatttool调试的时候出现过,就是那个值。第二个参数是要发送的数据。
关于介绍和安装方法 http://www.elinux.org/RPi_Bluetooth_LE
API文档:http://ianharvey.github.io/bluepy-doc/index.html
源码:https://github.com/IanHarvey/bluepy
安装过程:
sudo apt-get install python-pip
sudo apt-get install libglib2.0-dev
sudo pip install bluepy
简单例程:
#!/usr/bin/env python
from bluepy import btle
conn = btle.Peripheral("E3:47:55:D3:22:77", "random")
conn.writeCharacteristic(0x0011,"12345",withResponse=True)
1、其中Peripheral中的参数random很重要,之前一直没有添加这个参数,默认的是public,一直连接不上,后来添加了random,蓝牙可以和nrf51822连接了。是否需要加random需要看设备的地址类型, nRF51822采用的是Random Static address,在启动的时候协议栈从FICR里面读取作为设备的蓝牙地址.如果用户需要使用Public address,则需要使用sd_ble_gap_address_set()这个函数重新设定蓝牙地址。
2、参数0x0011是char的handle。之前在用gatttool调试的时候出现过,就是那个值。第二个参数是要发送的数据
关于public和random 的描述:
http://blog.csdn.net/sinat_23338865/article/details/52189538
http://blog.csdn.net/suxiang198/article/details/47730649
异常:bluepy.btle.BTLEException: Device disconnected
BluetoothError
测试代码: https://github.com/IJustLoveMyself/Raspberry-Pi/blob/master/test2/BLE-connect.py
https://github.com/IJustLoveMyself/Raspberry-Pi/blob/master/test2/BLE-trans.py (低功耗)
https://github.com/IJustLoveMyself/Raspberry-Pi/blob/master/test2/EDR-trans.py (普通蓝牙)