树莓派智能车AlphaBot教程12:蓝牙控制
一、安装蓝牙依赖库
升级安装蓝牙相关软件包
=== cpp代码: ===
sudo apt-get update
sudo apt-get upgrade -y
sudo apt-get dist-upgrade -y
sudo apt-get install pi-bluetooth bluez bluez-firmware blueman
最关键一点:添加pi用户到蓝牙组
=== cpp代码: ===
sudo usermod -G bluetooth -a pi
重启树莓派
=== cpp代码: ===
sudo reboot
二 ,开启蓝牙设备
启动/增加SPP
=== cpp代码: ===
sudo vi /etc/systemd/system/dbus-org.bluez.service
修改文件中这两个语句。
重启树莓派后,输入hciconfig命令(类似ifconfig命令)查看蓝牙服务
如果有看到hci0设备则蓝牙已经开启工作。如果没有则没有识别到蓝牙设备。
注意:如果/boot/config.txt文件中有 dtoverlay=pi3-miniuart-bt 这语句需要注释掉,否则蓝牙设备不能正常工作。
查看蓝牙适配器提供的各种功能
=== cpp代码: ===
pi@raspberrypi:~ $ sudo sdptool browse local
Browsing FF:FF:FF:00:00:00 ...
Service RecHandle: 0x10000
Service Class ID List:
"PnP Information" (0x1200)
Profile Descriptor List:
"PnP Information" (0x1200)
Version: 0x0103
Browsing FF:FF:FF:00:00:00 ...
Service Search failed: Invalid argument
Service Name: Serial Port
Service Description: COM Port
Service Provider: BlueZ
Service RecHandle: 0x10001
Service Class ID List:
"Serial Port" (0x1101)
Protocol Descriptor List:
"L2CAP" (0x0100)
"RFCOMM" (0x0003)
Channel: 1
Language Base Attr List:
code_ISO639: 0x656e
encoding: 0x6a
base_offset: 0x100
Profile Descriptor List:
"Serial Port" (0x1101)
Version: 0x0100
Service Name: Generic Access Profile
Service Provider: BlueZ
Service RecHandle: 0x10002
Service Class ID List:
"Generic Access" (0x1800)
Protocol Descriptor List:
"L2CAP" (0x0100)
PSM: 31
"ATT" (0x0007)
uint16: 0x0001
uint16: 0x0008
Service Name: Generic Attribute Profile
Service Provider: BlueZ
Service RecHandle: 0x10003
Service Class ID List:
"Generic Attribute" (0x1801)
Protocol Descriptor List:
"L2CAP" (0x0100)
PSM: 31
"ATT" (0x0007)
uint16: 0x0010
uint16: 0x0010
Service Name: AVRCP CT
Service RecHandle: 0x10004
Service Class ID List:
"AV Remote" (0x110e)
"AV Remote Controller" (0x110f)
Protocol Descriptor List:
"L2CAP" (0x0100)
PSM: 23
"AVCTP" (0x0017)
uint16: 0x0103
Profile Descriptor List:
"AV Remote" (0x110e)
Version: 0x0105
Service Name: AVRCP TG
Service RecHandle: 0x10005
Service Class ID List:
"AV Remote Target" (0x110c)
Protocol Descriptor List:
"L2CAP" (0x0100)
PSM: 23
"AVCTP" (0x0017)
uint16: 0x0103
Profile Descriptor List:
"AV Remote" (0x110e)
Version: 0x0104
三、链接蓝牙设备
输入如下命令进入蓝牙控制界面,(可进入界面输入help查看命令列表)
=== cpp代码: ===
sudo bluetoothctl
agent on
然后进入界面之后(可进入界面输入help查看命令列表)
=== cpp代码: ===
agent on
default-agent
scan on之后 就可以看到扫描得到的蓝牙设备的物理地址了,类似XX:XX:XX:XX:XX:XX之类的地址
配对使用以下命令(以下请把XX:XX:XX:XX:XX:XX替换为你自己设备的地址,android手机可以在设置->关于手机->状态信息中看到蓝牙地址。) pair XX:XX:XX:XX:XX:XX
配对之后把设备添加到信任列表 trust XX:XX:XX:XX:XX:XX
之后连接设备 connect XX:XX:XX:XX:XX:XX
最后quit退出就可以了,以后蓝牙设备开机后树莓派会自动进行连接。
四,手机端通过蓝牙发送数据到树莓派
运行如下命令后等待链接
=== cpp代码: ===
sudo rfcomm watch hci0
手机端打开蓝牙软件(例如 WS EDR),搜索蓝牙设备并链接到树莓派
如果没有搜索到树莓派蓝牙,可以运行如下命令开启蓝牙可发现。
另外打开一个终端运行如下命令可以看到/dev目录下有一个rfcomm0设备,只有蓝牙设备连接上树莓派后才有这个设备。
运行如下命令,用串口软件minicom 打开这个设备。(如果没有安装minicom,可以运行sudo apt-ge install minicom 安装)
=== cpp代码: ===
sudo minicom -D /dev/rfcomm0
minicom界面如下,此时按下手机中的方向键,minicom会接受到相应的指令。
按Ctrl+A,再按Z进入菜单,再按Q退出minicom。
四,蓝牙控制小车示例程序
废话也不多说,直接上代码。bluetooth.py文件
=== cpp代码: ===
#!/usr/bin/python
# -*- coding:utf-8 -*-
import serial
import time
import json
from AlphaBot import AlphaBot
LOW_SPEED = 30
MEDIUM_SPEED = 50
HIGH_SPEED = 80
Ab = AlphaBot()
BT = serial.Serial("/dev/rfcomm0",115200)
print('serial test start ...')
BT.flushInput()
try:
while True:
data = ""
while BT.inWaiting() > 0:
data += BT.read(BT.inWaiting())
if data != "":
#print data
try:
s = json.loads(data)
cmd = s.get("Forward")
if cmd != None:
if cmd == "Down":
BT.write("{\"State\":\"Forward\"}")
elif cmd == "Up":
BT.write("{\"State\":\"Stop\"}")
Ab.stop()
cmd = s.get("Backward")
if cmd != None:
if cmd == "Down":
BT.write("{\"State\":\"Backward\"}")
elif cmd == "Up":
BT.write("{\"State\":\"Stop\"}")
Ab.stop()
cmd = s.get("Left")
if cmd != None:
if cmd == "Down":
BT.write("{\"State\":\"Left\"}")
elif cmd == "Up":
BT.write("{\"State\":\"Stop\"}")
Ab.stop()
cmd = s.get("Right")
if cmd != None:
if cmd == "Down":
BT.write("{\"State\":\"Right\"}")
elif cmd == "Up":
BT.write("{\"State\":\"Stop\"}")
Ab.stop()
cmd = s.get("Low")
if cmd == "Down":
BT.write("{\"State\":\"Low\"}")
Ab.setPWMA(LOW_SPEED);
Ab.setPWMB(LOW_SPEED);
cmd = s.get("Medium")
if cmd == "Down":
BT.write("{\"State\":\"Medium\"}")
Ab.setPWMA(MEDIUM_SPEED);
Ab.setPWMB(MEDIUM_SPEED);
cmd = s.get("High")
if cmd == "Down":
BT.write("{\"State\":\"High\"}")
Ab.setPWMA(HIGH_SPEED);
Ab.setPWMB(HIGH_SPEED);
BT.flushInput()
except ValueError: #not json format
continue
except KeyboardInterrupt:
if BT!= None:
BT.close()
{程序分析]: 1.由上一节可知,蓝牙只需作为串口使用即可,不需要了解复杂的蓝牙协议。关于Python串口控制可以参考 树莓派系列教程13:Serial串口
2.BT = serial.Serial("/dev/rfcomm0",115200) 创建蓝牙设备示例,波特率115200 3.BT.flushInput() 清空接受缓存,丢弃之前的数据。 4.BT.inWaiting() 读取接受缓冲区是否有数据。 5.BT.read() 读取数据 6.BT.write() 发送数据 7.s = json.loads(data) 将json格式的字符转化为Python字典对象。如果蓝牙发送的字符串不是json格式,则会出现ValueError异常,数据丢弃继续接收。 8.cmd = s.get("Forward") 查询字典中是否有Forward键,返回的是键值,如果没有则返回None
运行如下命令启动程序
=== cpp代码: ===
sudo rfcomm watch hci0 1 python bluetooth.py
[命令分析]: 通过rfcomm 命令检测 hci0设备,当蓝牙设备连接到树莓派时,会创建/dev/rfcomm0 节点。 参数 1 表示有设备连接时创建一个进程来运行 python bluetooth.py 当连接成功时进程启动,连接断开时进程结束,或当进程结束时连接断开。