Ubuntu 20.04 连接 HC-05 蓝牙模块失败

博客地址:https://www.cnblogs.com/zylyehuo/

一、问题描述

在 Ubuntu 20.04 系统中连接 HC-05 蓝牙串口模块时,Windows 系统可以正常连接,但 Ubuntu 系统中会出现蓝牙可以搜索到、PIN 码输入正确、设备可以配对成功,但是连接后立即断开的情况。
具体表现包括:

  • 可以搜索到 HC-05;
  • PIN 码 1234 输入正确;
  • 配对成功;
  • bluetoothctl connect 连接失败;
  • rfcomm bind 无法生成 /dev/rfcomm0

扫描设备时,可以看到 HC-05:

bash 复制代码
Device 00:55:44:5D:3E:1B HC-05

输入 PIN 码 1234 后,配对成功:

text 复制代码
Pairing successful

查看设备信息:

bash 复制代码
bluetoothctl info 00:55:44:5D:3E:1B

设备状态如下:

text 复制代码
Name: HC-05
Paired: yes
Trusted: yes
Blocked: no
Connected: no
UUID: Serial Port (00001101-0000-1000-8000-00805f9b34fb)

这说明 HC-05 已经成功配对,并且提供蓝牙串口服务。
但是直接连接失败:

bash 复制代码
connect 00:55:44:5D:3E:1B

报错如下:

text 复制代码
Failed to connect: org.bluez.Error.Failed

继续尝试绑定蓝牙串口:

bash 复制代码
sudo rfcomm bind /dev/rfcomm0 00:55:44:5D:3E:1B 1

报错如下:

text 复制代码
RFCOMM TTY support not available

最终确认,该问题不是 PIN 错误,也不是 HC-05 配对失败,而是当前内核没有启用 RFCOMM TTY 支持,导致系统无法生成 /dev/rfcomm0


二、原因分析

检查当前内核配置:

bash 复制代码
sudo modprobe configs
zcat /proc/config.gz | grep -E "CONFIG_BT_RFCOMM|CONFIG_BT_RFCOMM_TTY"

输出结果:

text 复制代码
CONFIG_BT_RFCOMM=y
# CONFIG_BT_RFCOMM_TTY is not set

其中:

text 复制代码
CONFIG_BT_RFCOMM=y

表示系统支持 RFCOMM 蓝牙通信协议。

text 复制代码
# CONFIG_BT_RFCOMM_TTY is not set

表示系统不支持将 RFCOMM 蓝牙连接映射成 Linux TTY 串口设备。
也就是说,当前系统可以使用 RFCOMM 协议通信,但不能创建:

text 复制代码
/dev/rfcomm0

因此,传统蓝牙串口绑定方式不可用:

bash 复制代码
sudo rfcomm bind 0 00:55:44:5D:3E:1B 1

解决思路是绕过 /dev/rfcomm0,直接使用 Python 通过 RFCOMM Socket 与 HC-05 通信。
本文将该方法称为:
RFCOMM Socket 直连解析法


三、具体解决步骤

1. 进入 bluetoothctl

执行:

bash 复制代码
bluetoothctl

依次输入:

text 复制代码
power on
agent on
default-agent
scan on

扫描到 HC-05 后,会看到类似输出:

text 复制代码
Device 00:55:44:5D:3E:1B HC-05

本文中的 HC-05 蓝牙地址为:

text 复制代码
00:55:44:5D:3E:1B

实际使用时,需要将该地址替换成自己的 HC-05 地址。


2. 配对 HC-05

bluetoothctl 中执行:

text 复制代码
pair 00:55:44:5D:3E:1B

系统提示输入 PIN 码时,输入:

text 复制代码
1234

配对成功后会显示:

text 复制代码
Pairing successful

3. 将 HC-05 设置为信任设备

执行:

text 复制代码
trust 00:55:44:5D:3E:1B

成功后会显示:

text 复制代码
Changing 00:55:44:5D:3E:1B trust succeeded

退出 bluetoothctl

text 复制代码
quit

4. 确认 HC-05 状态

执行:

bash 复制代码
bluetoothctl info 00:55:44:5D:3E:1B

确认状态中包含以下内容:

text 复制代码
Paired: yes
Trusted: yes
Blocked: no
UUID: Serial Port (00001101-0000-1000-8000-00805f9b34fb)

其中:

text 复制代码
UUID: Serial Port

表示 HC-05 提供蓝牙串口服务。


5. 检查系统 RFCOMM 支持状态

执行:

bash 复制代码
sudo modprobe configs
zcat /proc/config.gz | grep -E "CONFIG_BT_RFCOMM|CONFIG_BT_RFCOMM_TTY"

当前系统输出为:

text 复制代码
CONFIG_BT_RFCOMM=y
# CONFIG_BT_RFCOMM_TTY is not set

这说明系统支持 RFCOMM 协议,但不能创建 /dev/rfcomm0


6. 查询 HC-05 的 RFCOMM 通道

执行:

bash 复制代码
sdptool browse 00:55:44:5D:3E:1B | grep -i -A 8 "Serial Port"

输出结果:

text 复制代码
"Serial Port" (0x1101)
Protocol Descriptor List:
  "L2CAP" (0x0100)
  "RFCOMM" (0x0003)
    Channel: 1

说明 HC-05 的 RFCOMM 通道是:

text 复制代码
Channel: 1

后续 Python 程序中需要设置:

python 复制代码
channel = 1

7. 清理蓝牙连接状态

执行:

bash 复制代码
bluetoothctl

进入后执行:

text 复制代码
scan off
disconnect 00:55:44:5D:3E:1B
quit

然后重启蓝牙服务:

bash 复制代码
sudo systemctl daemon-reload
sudo systemctl restart bluetooth
sudo hciconfig hci0 reset

检查是否还有残留连接:

bash 复制代码
hcitool con

正常情况下输出:

text 复制代码
Connections:

表示当前没有残留连接。


8. 创建 HC-05 数据接收和解析程序

新建 Python 文件:

bash 复制代码
gedit hc05_parse.py

写入以下完整代码:

python 复制代码
import socket
import time
import re

addr = "00:55:44:5D:3E:1B"
channel = 1


def parse_data(text):
    """
    解析 HC-05 发来的数据。

    示例数据:
    hear:0#,spo2:0#,temp:22.3#,step:8#,time:00:00:00#
    """

    result = {}

    # 如果数据前面存在乱码,则从第一个有效字段开始截取
    match = re.search(r"(hear|spo2|temp|step|time):", text)
    if match:
        text = text[match.start():]

    # 提取 key:value# 格式的数据
    items = re.findall(r"([a-zA-Z_]+):([^#,]+)#", text)

    for key, value in items:
        result[key] = value

    return result


while True:
    sock = socket.socket(
        socket.AF_BLUETOOTH,
        socket.SOCK_STREAM,
        socket.BTPROTO_RFCOMM
    )

    sock.settimeout(10)

    try:
        print("Connecting HC-05...")
        sock.connect((addr, channel))
        print("Connected")

        while True:
            data = sock.recv(1024)

            if not data:
                print("Disconnected")
                break

            text = data.decode("utf-8", errors="ignore").strip()
            print("Raw:", text)

            parsed = parse_data(text)

            if parsed:
                hear = parsed.get("hear")
                spo2 = parsed.get("spo2")
                temp = parsed.get("temp")
                step = parsed.get("step")
                time_value = parsed.get("time")

                print("Parsed:")
                print("  Heart:", hear)
                print("  SpO2:", spo2)
                print("  Temp:", temp)
                print("  Step:", step)
                print("  Time:", time_value)
                print("-" * 30)
            else:
                print("No valid data parsed")

    except Exception as e:
        print("Error:", e)
        print("Reconnect after 3 seconds...")
        time.sleep(3)

    finally:
        sock.close()

保存并退出:

text 复制代码
Ctrl + O
Enter
Ctrl + X

9. 运行程序

执行:

bash 复制代码
python3 hc05_parse.py

成功连接后会显示:

text 复制代码
Connecting HC-05...
Connected

接收到数据后会显示类似内容:

text 复制代码
Raw: hear:0#,spo2:0#,temp:22.3#,step:8#,time:00:00:00#
Parsed:
  Heart: 0
  SpO2: 0
  Temp: 22.3
  Step: 8
  Time: 00:00:00
------------------------------

实际测试中收到的数据为:

text 复制代码
Received: b'c.\x1c"hear:0#,spo2:0#,temp:22.3#,step:8#,time:00:00:00#\r\n'

虽然数据前面存在无效字符,但程序会自动从 hear:spo2:temp:step:time: 开始截取,因此可以正常解析后面的有效数据。


四、为什么 RFCOMM Socket 直连解析法可以使用

该方法可以使用的根本原因是:当前系统虽然不能生成 /dev/rfcomm0,但仍然支持 RFCOMM 协议。
系统内核配置为:

text 复制代码
CONFIG_BT_RFCOMM=y
# CONFIG_BT_RFCOMM_TTY is not set

其中:

text 复制代码
CONFIG_BT_RFCOMM=y

表示 RFCOMM 蓝牙通信协议可用。

text 复制代码
# CONFIG_BT_RFCOMM_TTY is not set

表示不能把 RFCOMM 映射成 Linux TTY 串口设备,也就是不能生成:

text 复制代码
/dev/rfcomm0

传统方式依赖 /dev/rfcomm0,例如:

bash 复制代码
sudo rfcomm bind 0 00:55:44:5D:3E:1B 1

因此会失败。
而 RFCOMM Socket 直连解析法不依赖 /dev/rfcomm0,它直接通过 Python 创建蓝牙 RFCOMM Socket:

python 复制代码
socket.socket(
    socket.AF_BLUETOOTH,
    socket.SOCK_STREAM,
    socket.BTPROTO_RFCOMM
)

然后直接连接 HC-05:

python 复制代码
sock.connect((addr, channel))

所以只要系统支持:

text 复制代码
CONFIG_BT_RFCOMM=y

并且 HC-05 提供 Serial Port 服务,就可以正常通信。


五、解决中可能遇到的问题

1. bluetoothctl connect 失败

现象:

text 复制代码
Failed to connect: org.bluez.Error.Failed

原因说明:
HC-05 是蓝牙串口模块,不一定需要通过 bluetoothctl connect 保持连接。只要已经完成配对和信任,Python 程序可以自己建立 RFCOMM 连接。
处理方法:
后续使用时不需要执行:

bash 复制代码
bluetoothctl connect 00:55:44:5D:3E:1B

直接运行 Python 程序即可。


2. 无法生成 /dev/rfcomm0

现象:

text 复制代码
RFCOMM TTY support not available

原因说明:
当前内核没有启用:

text 复制代码
CONFIG_BT_RFCOMM_TTY

检查结果为:

text 复制代码
CONFIG_BT_RFCOMM=y
# CONFIG_BT_RFCOMM_TTY is not set

因此不能使用:

bash 复制代码
sudo rfcomm bind 0 00:55:44:5D:3E:1B 1

处理方法:
使用 RFCOMM Socket 直连解析法,不依赖 /dev/rfcomm0


3. Python 连接时报 Device or resource busy

现象:

text 复制代码
OSError: [Errno 16] Device or resource busy

原因说明:
蓝牙设备或 HC-05 当前可能处于占用状态。
处理方法:

bash 复制代码
bluetoothctl

执行:

text 复制代码
scan off
disconnect 00:55:44:5D:3E:1B
quit

然后重启蓝牙:

bash 复制代码
sudo systemctl daemon-reload
sudo systemctl restart bluetooth
sudo hciconfig hci0 reset

检查残留连接:

bash 复制代码
hcitool con

确认只显示:

text 复制代码
Connections:

然后重新运行:

bash 复制代码
sudo python3 hc05_parse.py

4. 接收到的数据前面有乱码

现象:

text 复制代码
b'c.\x1c"hear:0#,spo2:0#,temp:22.3#,step:8#,time:00:00:00#\r\n'

原因说明:
蓝牙串口接收时可能会读到上一帧残留数据或非完整帧数据。
处理方法:
程序中从有效字段开始截取:

python 复制代码
match = re.search(r"(hear|spo2|temp|step|time):", text)
if match:
    text = text[match.start():]

这样可以自动丢弃前面的无效字符。


5. HC-05 已配对但无法收到数据

可以检查 HC-05 是否仍然处于正确状态:

bash 复制代码
bluetoothctl info 00:55:44:5D:3E:1B

正常状态应包含:

text 复制代码
Paired: yes
Trusted: yes
Blocked: no
Connected: no
UUID: Serial Port

然后确认通道:

bash 复制代码
sdptool browse 00:55:44:5D:3E:1B | grep -i -A 8 "Serial Port"

如果显示:

text 复制代码
Channel: 1

程序中就应设置:

python 复制代码
channel = 1

六、总结

本次问题并不是 PIN 错误,也不是 HC-05 无法配对,而是当前内核没有启用 RFCOMM TTY 支持。
传统蓝牙串口方式需要:

text 复制代码
/dev/rfcomm0

但当前系统不支持创建该设备。
内核配置显示:

text 复制代码
CONFIG_BT_RFCOMM=y
# CONFIG_BT_RFCOMM_TTY is not set

因此最终采用 RFCOMM Socket 直连解析法
该方法的优点是:

  1. 不需要 /dev/rfcomm0
  2. 不需要重新编译内核
  3. 可以直接连接 HC-05
  4. 可以直接接收并解析蓝牙串口数据
  5. 适合 Jetson / Orin 这类未启用 RFCOMM TTY 的系统

最终运行结果证明,Ubuntu 20.04 / Jetson Orin 可以正常接收 HC-05 发来的数据:

text 复制代码
hear:0#,spo2:0#,temp:22.3#,step:8#,time:00:00:00#

解析后可以得到:

text 复制代码
Heart: 0
SpO2: 0
Temp: 22.3
Step: 8
Time: 00:00:00

至此,HC-05 蓝牙串口通信问题解决。

相关推荐
爱凤的小光2 个月前
ROS之CameraInfo---个人学习篇
camera·ros1
zylyehuo4 个月前
Windows11 & Ubuntu20.04 双系统
ros1
zylyehuo4 个月前
Windows11 制作 Ubuntu 20.04 系统盘
ros1
zylyehuo4 个月前
Ubuntu20.04 安装声卡驱动
ros1
zylyehuo5 个月前
error: no matching function for call to ‘ros::NodeHandle::param(const char [11], std::string&, const char [34])’
c++·ros1
zylyehuo5 个月前
新写的launch文件不能用tab补全
ros1
zylyehuo5 个月前
ROS1 noetic 中将 Unitree G1 基于 Gazebo/RViz 关节联动【使用一个launch文件启动】
ros1·humanoid
zylyehuo5 个月前
ROS1 noetic 中将 Unitree G1 的 URDF 导入 Gazebo/RViz
ros1
奔跑的花短裤6 个月前
ROS2安装
ros·ros2·ros1